我有两个看起来像这样的表:
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个“类”。所以,虽然数据看起来很玩具,但请不要玩具解决方案。
答案 0 :(得分:3)
参考this excellent page on selecting the 'greatest-n-per-group',这是我提出的查询。回想起来,它与@ BassamMehanni的答案基本相同,只是MySQL中没有ROW_NUMBER()
函数。
这假设您有表class
和toppers
。
注意:如果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);
基本上,这个查询:
class
行进行编号。也就是说,对每个班级中的每个学生进行排名。class
为rank
的{{1}}行。对于第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。