Reputation: 115
Let's say I have this table:
id; date; units
1; Jan 1; 1
2; Jan 2; 4
3; Feb 9; 6
4; Mar 1; 1
5; Mar 4; 2
How can I now calculate the "accumulated_month" column accordingly? The calculation should start anew with every new month.
id; date; units; accumulated_month
1; Jan 1; 1; 1
2; Jan 2; 4; 5
3; Feb 9; 6; 6
4; Mar 1; 1; 1
5; Mar 4; 2; 3
All I manage to get is this:
id; date; units; accumulated_month
1; Jan 1; 1; 5
2; Jan 2; 4; 5
3; Feb 9; 6; 6
4; Mar 1; 1; 3
5; Mar 4; 2; 3
Upvotes: 2
Views: 1975
Reputation: 2728
Run this:
SELECT
t1.id,
t1.date,
t1.units,
SUM(t2.units) accumulated_month
FROM t t1
JOIN t t2
ON date_trunc('month', t1.date) = date_trunc('month', t2.date)
AND t2.date <= t1.date
GROUP BY t1.id, t1.date, t1.units
ORDER BY t1.id
Simplified SQL:
SELECT
t1.*, SUM(t2.units) accumulated_month
FROM t t1
JOIN t t2
ON date_trunc('month', t1.date) = date_trunc('month', t2.date)
AND t2.date <= t1.date
GROUP BY t1.id
ORDER BY t1.id
The logic behind is to JOIN
the table with itself. Then for each row of t1
JOIN
all rows in t2
that satisfies both (AND
):
With those ON
constraints each row in t1
will be JOIN
with accumulated in that month so far. So without grouping, you'd get something like:
╔════╦════════════╦═══════╦════════════╦══════════╗
║ id ║ date ║ units ║ t2_date ║ t2_units ║
╠════╬════════════╬═══════╬════════════╬══════════╣
║ 1 ║ 2016-01-01 ║ 1 ║ 2016-01-01 ║ 1 ║
║ 2 ║ 2016-01-02 ║ 4 ║ 2016-01-01 ║ 1 ║
║ 2 ║ 2016-01-02 ║ 4 ║ 2016-01-02 ║ 4 ║
║ 3 ║ 2016-02-09 ║ 6 ║ 2016-02-09 ║ 6 ║
║ 4 ║ 2016-03-01 ║ 1 ║ 2016-03-01 ║ 1 ║
║ 5 ║ 2016-03-04 ║ 2 ║ 2016-03-01 ║ 1 ║
║ 5 ║ 2016-03-04 ║ 2 ║ 2016-03-04 ║ 2 ║
╚════╩════════════╩═══════╩════════════╩══════════╝
After GROUP BY t1.id
you can SUM(t2.units)
to get what you expect.
Upvotes: 1
Reputation: 125244
create table t (id int, date date, units int);
insert into t (id, date, units) values
(1, '2016-01-01', 1),
(2, '2016-01-02', 4),
(3, '2016-02-09', 6),
(4, '2016-03-01', 1),
(5, '2016-03-04', 2);
Not clear if you want the month total or a running total within the month. For the month total:
select
id, date, units,
sum(units) over (partition by date_trunc('month', date)) as acumm
from t
order by 1,2
;
id | date | units | acumm
----+------------+-------+-------
1 | 2016-01-01 | 1 | 5
2 | 2016-01-02 | 4 | 5
3 | 2016-02-09 | 6 | 6
4 | 2016-03-01 | 1 | 3
5 | 2016-03-04 | 2 | 3
If you want a running total within the month then add an order by to the window function:
select
id, date, units,
sum(units) over (
partition by date_trunc('month', date)
order by id
) as acumm
from t
order by 1,2
;
id | date | units | acumm
----+------------+-------+-------
1 | 2016-01-01 | 1 | 1
2 | 2016-01-02 | 4 | 5
3 | 2016-02-09 | 6 | 6
4 | 2016-03-01 | 1 | 1
5 | 2016-03-04 | 2 | 3
Upvotes: 2