Обращаясь к на этой превосходной странице по выбору 'great-n-per-group' , вот запрос, который я придумал.Оглядываясь назад, он в основном идентичен ответу @ BassamMehanni, за исключением того, что в MySQL нет функции ROW_NUMBER()
.
Это предполагает, что у вас есть таблицы class
и toppers
.
Решение:
Примечание: если у вас есть основной идентификатор в таблице class
, который не является составной комбинацией (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
равно <= NumToppers
, для каждого класса. - Обновляет их.
Для шага 1 см. Следующее (по ссылке, на которую я вас ссылался):
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
(после сортировки по классу и убыванию оценки) иустанавливает rank
в 1, если мы находимся в новом классе, или rank+1
, если мы в одном и том же классе.
Для шага 2 мы выполняем JOIN с toppers
наclass
и выберите верхние 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
Наконец, мы обновим эти условия (шаг 3).Однако мы должны сделать UPDATE class
явно, поэтому мы должны добавить дополнительно JOIN
шага 2 с class
:
set @class='';
set @rank=1;
UPDATE class # NEW
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 # NEW (join condition)
AND c.Name=class.Name # NEW (join condition)
LEFT JOIN toppers
ON c.Class=toppers.Class
SET top = (CASE WHEN rank <= NumToppers THEN 'Y' ELSE 'N' END); # NEW
Если у вас есть основной идентификатор на class
, который предпочтительноне составной (т. е. идентификатор из одного столбца), а затем присоединитесь к нему.