MySQL中每个班级的前k名学生

时间:2012-01-10 00:15:47

标签: mysql limit greatest-n-per-group

我有两个看起来像这样的表:

Class  Name  Score  Top
1      Amy    90     X
1      Ben    70     X
1      Chu    80     X
2      Don    60     X
2      Elf    65     X
2      Fez    75     X
2      Ges    35     X
2      Han    40     X

Class NumToppers
1      2
2      3

我希望从每个班级中找到Top“NumToppers”并相应地更新“Top”字段:

Class  Name  Score  Top
1      Amy    90     Y
1      Ben    70     N
1      Chu    80     Y
2      Don    60     Y
2      Elf    65     Y
2      Fez    75     Y
2      Ges    35     N
2      Han    40     N

我的真实数据中有100个“类”。所以,虽然数据看起来很玩具,但请不要玩具解决方案。

1 个答案:

答案 0 :(得分:3)

参考this excellent page on selecting the 'greatest-n-per-group',这是我提出的查询。回想起来,它与@ BassamMehanni的答案基本相同,只是MySQL中没有ROW_NUMBER()函数。

这假设您有表classtoppers

解决方案:

注意:如果class表上的主要ID不是复合(Class,Name,Score)组合,请将其用于标记为#@@的加入条件。

set @class='';
set @rank=1;
UPDATE class         
LEFT JOIN 
  (SELECT Class,Name,Score,
       @rank:=if(@class=Class,@rank+1,1) as rank, 
       @class:=Class as dummy 
  FROM class ORDER BY Class,Score DESC) c
ON c.Class=class.Class AND c.Score=class.Score  #@@
   AND c.Name=class.Name                        #@@
LEFT JOIN toppers
ON c.Class=toppers.Class
SET Top = (CASE WHEN rank <= NumToppers THEN 'Y' ELSE 'N' END); 

说明

基本上,这个查询:

  1. 在每个班级中按分数从上到下对class行进行编号。也就是说,对每个班级中的每个学生进行排名。
  2. 为每个班级选择classrank的{​​{1}}行。
  3. 更新这些。
  4. 对于第1步,请参阅以下内容(来自我推荐的链接):

    <= NumToppers

    这会查看set @class=''; set @rank=1; SELECT Class,Name,Score, @num:=if(@class=Class,@rank+1,1) as rank, @class:=Class as dummy FROM class ORDER BY Class,Score DESC; 的每一行(按类别和降序排序后),如果我们要参加新课程,则将class设置为1,或{{1}如果我们在同一个班级内。

    对于第2步,我们在rank上与rank+1进行联接,并为每个类选择前toppers行:

    class

    最后,我们更新这些条件(步骤3)。但是,我们必须明确NumToppers,因此我们必须使用set @class=''; set @rank=1; SELECT * # NEW FROM toppers # NEW LEFT JOIN # NEW (SELECT Class,Name,Score, #\ @rank:=if(@class=Class,@rank+1,1) as rank, # |(same as step 1) @class:=class as dummy # | FROM class ORDER BY Class,Score DESC) c #/ ON c.Class=toppers.Class # NEW WHERE rank <= NumToppers; # NEW 添加额外的UPDATE class步骤2:

    JOIN

    如果class上的主要ID最好不是复合(即单列ID),那么请加入该ID。