Mysql 检索每个名称前n-4个点的总和
如何检索每个名称前n-4个点的总和。我们可以在一个SQL语句中完成这项工作,而不使用用户定义的会话变量吗 输入: 看看下面或下面 输出: 看看下面或下面 总结:Mysql 检索每个名称前n-4个点的总和,mysql,sql,database,Mysql,Sql,Database,如何检索每个名称前n-4个点的总和。我们可以在一个SQL语句中完成这项工作,而不使用用户定义的会话变量吗 输入: 看看下面或下面 输出: 看看下面或下面 总结: 杰夫=7+5+4+4=20 Kat=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 | |凯特
杰夫=7+5+4+4=20
Kat=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 |
±±±±+
谢谢 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.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;
这考虑到了任何联系。严格地说,案例
是不必要的,但我认为它使逻辑更加明确
编辑:
如果你只想要倒数第四名(你的问题不清楚),同样的方法也适用:
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;
唯一的区别是颠倒顺序。看看MySQL是否在子查询中不允许
LIMIT
;为什么它允许内部合并()
+1嗨,谢谢,我很确定这会返回前4个元素,而不是n-4(n是作业的数量)
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;