Reputation: 1214
I have an account transaction table that lists all activities in the account.
id qty
1 100
2 200
3 -50
4 20
The id column is an indecation of real time activities as 2
hapend after 1
, and 4
happened after 3
.
I need to add a column which per each row gives the current total sum:
id qty total_sum
1 100 100 / 0 + 100
2 200 300 / 100 + 200
3 -50 250 / 300 - 50
4 20 270 / 250 + 20
This is simple enough. However my table is huge, it contains very old rows which thier data isn't neccecry correct. To avoid it, I would like to calculate the sum from buttom to top, so that at least the newest records will have the currect values. In my case it is doable as for each user I always save the current updated total_sum for today... so I have a value to begin with.
In that case (+
will be consider as -
and -
as +
) what I get is:
id qty total_sum
1 100 0 / 100 - 100
2 200 100 / 300 - 200
3 -50 300 / 250 + 50
4 20 250 / init_value - 20
The problem is that in each row total_sum
present the sum before the action on the row was done. for example in row 2 it shows total_sum=100
which is before the action of row 2 was proccessed.
How can I fix it to show the first total_sum column but calculated from buttom?
basicly what i need is:
id qty total_sum
1 100 100
2 200 300
3 -50 250
4 20 init_value (which is 270)
This is my code:
SELECT id,qty,(select init_value from x where .....)
- Sum(a.qty)OVER(ORDER BY id DESC) as total_sum
FROM a
ORDER BY id ASC
How can I fix it? (Postgresql 9.3)
Upvotes: 2
Views: 74
Reputation: 10525
You need to use LEAD/LAG function to access the next/previous quantity and use that in SUM.
PostgreSQL 9.3 Schema Setup:
create table myt(
id_ integer,
qty_ integer
);
insert into myt values(1,100);
insert into myt values(2,200);
insert into myt values(3,-50);
insert into myt values(4,20);
Query 1:
select id_, qty_,
lead(qty_) over (order by id_) qty2
from myt
order by id_
| id_ | qty_ | qty2 |
|-----|------|--------|
| 1 | 100 | 200 |
| 2 | 200 | -50 |
| 3 | -50 | 20 |
| 4 | 20 | (null) |
Query 2:
select id_, qty_,
270 - coalesce((sum(qty2) over (order by id_ desc)),0) total_sum
from (
select id_, qty_,
lead(qty_) over (order by id_) qty2
from myt
) c
order by id_
| id_ | qty_ | total_sum |
|-----|------|-----------|
| 1 | 100 | 100 |
| 2 | 200 | 300 |
| 3 | -50 | 250 |
| 4 | 20 | 270 |
Upvotes: 2