【问题标题】:Rank users in mysql by their total points across multiple rows在 mysql 中按用户在多行中的总分对用户进行排名
【发布时间】:2016-04-13 10:45:06
【问题描述】:

我有与此问题中描述的非常相似的要求。

Rank users in mysql by their points

唯一的区别在于我的数据。上述问题的数据表中每个学生只有一行。但在我的情况下,表格可能包含像这样的单个学生的多行

  • 学生1分80
  • 学生2分77.5
  • 学生2分4.5
  • 学生3分77
  • 学生4分77

所以现在应该根据用户拥有的点数(总数)SUM 计算排名。所以在这种情况下,结果将是。

  • 学生 2 排名 1 82 分
  • 学生 1 排名 2 80 分
  • 学生 3 排名 3 77 分
  • 学生 4 排名 3 77 分

SQL Fiddle for data

我用上述问题的解决方案尝试了几件事,但无法得到结果。任何帮助将不胜感激。

【问题讨论】:

  • 使用该表中的解决方案,但不是原始表,而是对计算SUM(points) ... GROUP BY student 的子查询的结果进行排名`
  • 请至少展示您尝试过的一种方法,以便我们帮助您从错误中吸取教训。我们不会为你写的。

标签: mysql


【解决方案1】:

在我之前的回答中使用相同的查询,只需将表 student 更改为子查询以组合每个学生的所有记录

change [student er]  for 

(SELECT `id`, SUM(`points`) as `points`
 FROM students 
 GROUP BY `id`) er

SQL DEMO

select er.*,
       (@rank := if(@points = points, 
                    @rank, 
                    if(@points := points,    
                       @rank + 1, 
                       @rank + 1                       
                      )
                   )                  
       ) as ranking
from (SELECT `id`, SUM(`points`) as `points`
      FROM students 
      GROUP BY `id`) er cross join
     (select @rank := 0, @points := -1) params
order by points desc;

输出

| id | points | ranking |
|----|--------|---------|
|  5 |     91 |       1 |
|  6 |     81 |       2 |
|  1 |     80 |       3 |
|  2 |     78 |       4 |
|  3 |     78 |       4 |
|  4 |     77 |       5 |
|  7 |     66 |       6 |
|  8 |     15 |       7 |

【讨论】:

  • 我读到你对 mySQL 版本和 sqlFiddle 有一些问题,希望这对你有用。
  • @Sachin @ JuanCarlosOropeza 我赞成这个答案,因为我认为双 IF 是个好主意,但排名结果是错误的。您的排名是 1-2-3-4-4-5,但正确的排名是 1-2-3-4-4-6。我的代码给出了正确的排名。
  • 不,@genespos,我认为排名 1-2-3-4-4-5 很好,这就是我想要的。正如您所说,在您的结果中缺少 Rank 5..
  • @Sachin 在奥运会比赛中,如果第一个参赛者有 100 分,那么两个参赛者有 90 分,另一个有 80 分:第一个获得金牌,获得 90 分的两个获得银牌80分没有拿到铜牌,因为他是第4。但如果这对你有好处:没问题。 ;)
  • @genespos 这个叫做dense_rank,你可以在这里看到区别。 stackoverflow.com/questions/11183572/…
【解决方案2】:

试试这个:

select id, points, @row := ifnull(@row, 0) + diff rank
from (select *, ifnull(@prev, 0) != points diff, @prev := points
      from (select id, sum(points) points
            from students
            group by 1
            order by 2 desc) x) y

SQLFiddle

【讨论】:

  • 你没有显示排名。
  • @Sachin:虽然您可以让 MySQL 使用用户变量包含排名(正如 Bohemian 在他的编辑中刚刚展示的那样),但在获取每条记录时,通常更容易在应用程序级别添加排名计数器从结果集中。
  • 这项工作几乎没有问题,但是当两个学生的分数相等时就会出现问题。看看学生 2 和 3 各有 78 分。他们都应该有4而不是45sqlfiddle.com/#!9/95dff/15
  • @sachin 是的 - 我一直在努力 - 尝试最新的编辑
  • 有点奇怪,但它适用于 SqlFiddle,但不适用于 MySql 5.6.22 的 PhpMyAdmin。
【解决方案3】:

编辑: (这应该有效)

SELECT I.Id, I.Points, Rk.Rank
FROM
(SELECT Id, Points, @Rk := @Rk+1 As Rank
FROM (SELECT id, SUM(points) AS Points
      FROM students
      GROUP BY id
      ORDER BY Points DESC) As T,
      (SELECT @Rk := 0) AS Rk) As I
INNER JOIN
(SELECT * 
FROM (
    SELECT Id, Points, @Rk2 := @Rk2+1 As Rank
    FROM (SELECT id, SUM(points) AS Points
          FROM students
          GROUP BY id
          ORDER BY Points DESC) As T1,
          (SELECT @Rk2 := 0) AS Rk) AS T2
GROUP BY Points) As Rk
USING(Points)

输出将是:

| Id | Points |   Rank  |
|----|--------|---------|
|  5 |     91 |       1 |
|  6 |     81 |       2 |
|  1 |     80 |       3 |
|  2 |     78 |       4 |
|  3 |     78 |       4 |
|  4 |     77 |       6 |
|  7 |     66 |       7 |
|  8 |     15 |       8 |

在第 4 位的两个 Id 之后,您将获得第 6 位,因为 5 个 Id 在第 6 位之前。

【讨论】:

  • 当有平局时,这不会给出相同的排名。波西米亚人的回答确实如此。
  • @Barmar 这可能是我的错,但我在我的电脑上测试了 Bohemian 的答案,它返回 1 作为所有行的 Rank。你测试过吗?
  • 我看了他的 sqlfiddle
  • @Barmar 这是真的!它适用于 SqlFiddle,但不适用于 MySql 5.0.11 的 PhpMyAdmin
  • 这是一个相当老的 MySQL 版本。
猜你喜欢
  • 2015-05-05
  • 1970-01-01
  • 2020-04-07
  • 1970-01-01
  • 1970-01-01
  • 2020-03-30
  • 1970-01-01
  • 2015-06-23
  • 1970-01-01
相关资源
最近更新 更多