检索每个名称mySQL的前n-4个点的总和

时间:2018-10-27 20:33:18

标签: mysql sql database

如何检索每个名称前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 |
±-----±-----------±------- +

谢谢!

1 个答案:

答案 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;

唯一的区别是颠倒顺序。