SQL中当前行和下一行的累计总和

问题描述

问题 - 下表显示了给定年份前九个月员工的月薪。由此,编写一个查询以返回一个表格,该表格显示了该员工在上半年的每个月以及随后两个月的工资滚动总和,并按时间顺序排列。

Oracle sql 中的问题代码

create table salary (month int,salary int);
insert into salary values (1,2000);
insert into salary values (2,3000);
insert into salary values (3,5000);
insert into salary values (4,4000);
insert into salary values (5,2000);
insert into salary values (6,1000);
insert into salary values (7,2000);
insert into salary values (8,4000);
insert into salary values (9,5000);

我有解决方代码,但我根本无法理解。例如,这部分代码是做什么的?

ON s1.month <= s2.month 
AND s1.month > s2.month - 3

有人可以解释一下吗?

解决方代码

SELECT s1.month,sum(s2.salary) AS salary_3mos
FROM salary s1
JOIN salary s2
ON s1.month <= s2.month 
AND s1.month > s2.month - 3
GROUP BY 1
HAVING s1.month < 7
ORDER BY 1 ASC;

解决方法

使用窗口函数:

select s.*,sum(salary) over (order by month rows between current row and 2 following)
from salary s
order by month;

或者:

select s.*,salary + lead(salary) over (order by month) + lead(salary,2) over (order by month)
from salary s
order by month;

如果您真的想将计算限制在前六个月,您可以包含一个 case 表达式。

,

您当前的解决方案使用自联接方法。这是加入条件:

ON s1.month <= s2.month AND s1.month > s2.month - 3

这会将左侧的每个月的记录与右侧的三个记录配对,这些记录要么是同月的,要么是不超过 2 个月的。例如,对于第三个月,上述连接将生成以下中间表:

s1.month | s2.month | s2.salary
3        | 3        | 5000
3        | 4        | 4000
3        | 5        | 2000

然后,您的查询按 s1.month 进行聚合,取 s2.salary 的总和,得出:

s1.month | salary_3mos
3        | 11000

请注意,您当前的 HAVING 子句中的逻辑也可以移到 WHERE 子句中。要查看使用窗口函数解决问题的其他一些方法,请参阅@Gordon 的答案。