MySQL:如何获得系列赛每个事件的排行榜位置

时间:2018-07-02 11:49:25

标签: mysql sql

我具有以下数据结构(简化):

Users:
    ID
    Name

Events:
    ID
    Date

Results:
    ID
    User ID (foreign key)
    Event ID (foreign key)
    Points: (int)

我想知道(最有效的方法):

  • 与其他用户相比,如何获得用户在“联盟”中的位置。以及-如果可能的话,使用一个查询(或子查询),如何按事件将其细分,例如在第一事件,第二事件,第三事件等之后的用户位置。

我可以通过以下方式获得排行榜:

select users.name, SUM(results.points) as points
from results
inner join users on results.user_id = users.id
group by users.id
order by points DESC

但是,我想知道用户的位置,而不必尽可能返回整个表格。

编辑:我提供了一些示例数据here

理想的输出:

| User ID | Rank  |
| 3       | 1     |
| 1       | 2     |
| 2       | 3     |

和类似的东西(不是完全一样,它很灵活,只是显示每个事件的用户排名)

| User ID | After Event | Rank  |
| 1       | 1           | 1     |
| 1       | 2           | 1     |
| 1       | 3           | 2     |
| 2       | 1           | 2     |
| 2       | 2           | 2     |
| 2       | 3           | 1     |
| 3       | 1           | 3     |
| 3       | 2           | 3     |
| 3       | 3           | 3     |

2 个答案:

答案 0 :(得分:2)

MySQL 8.0+支持window functions,因此可以方便地使用dense_rank()


MySQL在8.0解决方案下

由于您的版本是5.7,因此您可以像下面这样模仿:

select 
  t.id,
  CASE WHEN @prevRank = points THEN @currRank
       WHEN @prevRank := points THEN @currRank := @currRank + 1
   END AS rank
from (
  select users.id, SUM(results.points) as points
  from results
  inner join users on results.user_id = users.id
  group by users.id
  order by points DESC
  ) t
  cross join (SELECT @currRank := 0, @prevRank := NULL) r

如果您需要特定user的数据,请添加一个WHERE条件以过滤外部查询中的其他所有人:

select *
from (
<< above query here >>
) t
where id = ? -- your id here

MySQL 8.0+解决方案

rank是保留关键字,因此在命名列时需要反引号。我们正在使用dense_rank窗口函数,该函数将基于获得的点的od降序分配等级:

select id, dense_rank() over (order by points desc) as `rank`
from (
  select users.id, SUM(results.points) as points
  from results
  inner join users on results.user_id = users.id
  group by users.id
  ) t
order by `rank`

答案 1 :(得分:0)

SET @rowno = 0;
select UserID, max(points), @rowno:=@rowno+1 as rank  from 
(
select users.id as UserID ,users.name as users_name,events.name, SUM(results.points) as points
from results
inner join users on results.user_id = users.id
inner join events on results.event_id= events.id
group by users.id,events.name,users.name
order by points DESC
) as T
group by UserID

order by max(points) desc