简体   繁体   中英

Cumulating sum of current row and next row in SQL

Question - The following table shows the monthly salary for an employee for the first nine months in a given year. From this, write a query to return a table that displays, for each month in the first half of the year, the rolling sum of the employee's salary for that month and the following two months, ordered chronologically.

Question Code in 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);

I have the solution code but I am not able to understand it at all. For example, what this part of the code does?

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

Could someone please explain?

Solution Code:

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;

Use window functions:

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

Or:

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

If you really want to limit the calculate to the first six months, you can include a case expression.

Your current solution uses a self-join approach. Here is the join criteria:

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

This will pair each month's record on the left with the three records on the right which are either on the same month or no more than 2 months ahead. For example, for the third month, the above join would generate the following intermediate table:

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

Then, your query aggregates by s1.month , taking the sum of the s2.salary , to give:

s1.month | salary_3mos
3        | 11000

Note that the logic in your current HAVING clause might as well be moved into the WHERE clause. To see some other ways to approach your problem using window functions, see the answer by @Gordon.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM