Самое простое решение в MySQL 8+:
select name, sum(points)
from (select t.*, row_number() over (partition by name order by points desc) as seqnum
from t
) t
where seqnum <= 4
group by name;
В более ранних версиях MySQL вам нужно было выполнять больше работы.Казалось бы, что-то вроде этого решит вашу проблему:
select t.name, sum(t.points)
from t
where t.assignment in (select t2.assignment
from t t2
where t2.name = t.name
order by t2.points desc
limit 4
)
group by t.name;
Но MySQL не поддерживает этот синтаксис.Если у вас не было дубликатов для точек, это сработало бы:
select t.name, sum(t.points)
from t
where t.points >= coalesce( (select t2.points
from t t2
where t2.name = t.name
order by t2.points desc
limit 1 offset 3
), 0)
group by t.name;
Но если 4-я и 5-я строки имеют одинаковые точки, то в сумме будет более 4 строк.
Теперь вы можете решить эту проблему с помощью переменных.,,но вместо этого мы можем адаптировать последнее решение:
select t.name,
(case when count(*) = 4 then sum(t.points)
else sum(t.points) - (count(*) - 4) * min(t.points)
end)
from t
where t.points >= coalesce( (select t2.points
from t t2
where t2.name = t.name
order by t2.points desc
limit 1 offset 3
), 0)
group by t.name;
Это учитывает любые связи.Строго говоря, case
не является необходимым, но я думаю, что это делает логику явной.
РЕДАКТИРОВАТЬ:
Если вы хотите все, кроме нижних четырех (ваш вопрос не ясен), тот же метод работает:
select t.name,
(case when count(*) = 4 then sum(t.points)
else sum(t.points) - (count(*) - 4) * min(t.points)
end)
from t
where t.points >= coalesce( (select t2.points
from t t2
where t2.name = t.name
order by t2.points asc
limit 1 offset 3
), 0)
group by t.name;
Единственная разница заключается в изменении порядка на.