如何检索每个名称前n-4个点的总和。我们可以在不使用用户定义的会话变量的情况下在一条SQL语句中执行此操作吗?
输入: 看下面或Here (clearer pic)
输出: 看下面或Here (clearer pic)
摘要:
杰夫= 7 + 5 + 4 + 4 = 20
凯特= 8 + 5 + 5 + 4 = 22
尼尔= 10 + 7 + 5 + 0 = 22
瑞克= 9 + 8 + 3 + 2 = 22
输入数据库:
±-----±-----------±------- +
|姓名|作业|点|
±-----±-----------±------- +
|杰夫| 1 | 7 |
|杰夫| 2 | 5 |
|杰夫| 3 | 3 |
|杰夫| 4 | 4 |
|杰夫| 5 | 4 |
|吉| 1 | 4 |
|吉| 2 | 8 |
|吉| 3 | 5 |
|吉| 4 | 3 |
|吉| 5 | 5 |
|尼尔| 1 | 5 |
|尼尔| 2 | 7 |
|尼尔| 3 | 10 |
|尼尔| 4 | 0 |
|尼尔| 5 | 0 |
|瑞克1 | 2 |
|瑞克2 | 1 |
|瑞克3 | 8 |
|瑞克4 | 3 |
|瑞克5 | 9 |
±-----±-----------±------- +
输出:
±-----±-----------±------- +
|姓名|作业|点|
±-----±-----------±------- +
|杰夫| 20 |
|吉| 22 |
|尼尔| 22 |
|瑞克22 |
±-----±-----------±------- +
谢谢!
答案 0 :(得分:1)
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行。
现在,您可以使用variables解决此问题。 。 。但是,我们可以采用最后一种解决方案:
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;
唯一的区别是颠倒顺序。