I have a table with monthly amounts per ID, where in some of these months an invoice takes place.
My table looks like:
ID | Date | Invoiced | Amount |
---|---|---|---|
AAA | 2023-01 | 0 | 10 |
AAA | 2023-02 | 0 | 15 |
AAA | 2023-03 | 1 | 15 |
AAA | 2023-04 | 0 | 10 |
AAA | 2023-05 | 0 | 10 |
AAA | 2023-06 | 1 | 10 |
BBB | 2022-05 | 0 | 40 |
BBB | 2022-06 | 1 | 20 |
BBB | 2022-07 | 0 | 30 |
BBB | 2022-08 | 1 | 30 |
I need to have the rows only per ID with the invoice months, where we sum over the previous amounts since the last invoice.
What I want to have:
ID | Date | Invoiced | Amount |
---|---|---|---|
AAA | 2023-03 | 1 | 40 |
AAA | 2023-06 | 1 | 30 |
BBB | 2022-06 | 1 | 60 |
BBB | 2022-08 | 1 | 60 |
How this can be done in postgresql? I started with the query below, but it gives not yet what I need.
SELECT "ID", "Date", "Invoiced"
, sum(Amount) OVER (PARTITION BY "Invoiced" ORDER BY "Id", "Date") AS Amount
FROM Table
3
Answers
We can use a combination of
LAG()
andSUM()
as window functions, to create a pseudo group for each invoice period, for eachID
:Demo
You have a gaps and islands problem, you could use
SUM()
as window function in descending order, to give a unique id to each successive group of rows (0 values then 1) :For completeness, here’s one with correlated scalar subqueries: demo
To get more columns from the lookback, it would have to be moved down to
FROM
section as aLATERAL
subquery – works the same, but added columns make it no longer scalar, so it can’t remain in theSELECT
list.Here’s a similar thread where you can find a few performance tests comparing the two, in the comments. Long story short, window functions are simply the right tool for this task – less typing, higher performance. Still, alternatives are always worth a mention.