Reputation: 1242
I'm running PostgreSQL 9.4 and have the following table structure for invoicing:
id BIGINT, time UNIX_TIMESTAMP, customer TEXT, amount BIGINT, status TEXT, billing_id TEXT
I hope I can explain my challenge correctly.
A invoice record can have 2 different status; begin
, ongoing
and done
.
Several invoice records can be part of the same invoice line, over time.
So when an invoice period begins, a record is started with status begin
.
Then every 6 hour there will be generated a new record with status ongoing
containing the current amount spend in amount
.
When an invoice is closed a record with status done
is generated with the total amount spend in column amount
. All the invoice records within the same invoice contains the same billing_id
.
To calcuate a customers current spendings I can run the following:
SELECT sum(amount) FROM invoice_records where id = $1 and time between '2017-06-01' and '2017-07-01' and status = 'done'
But that does not take into account if there's an ongoing invoice which are not closed yet.
How can I also count the largest billing_id with no status done
?
Hope it make sense.
Upvotes: 0
Views: 579
Reputation: 94894
Per invoice (i.e. billing_id
) you want the amount of the record with status = 'done'
if such exists or of the last record with status = 'ongoing'
. You can use PostgreSQL's DISTINCT ON
for this (or use standard SQL's ROW_NUMBER
to rank the records per invoice).
SELECT DISTINCT ON (billing_id) billing_id, amount
FROM invoice_records
WHERE status IN ('done', 'ongoing', 'begin')
ORDER BY
billing_id,
CASE status WHEN 'done' THEN 1 WHEN 'ongoing' THEN 2 ELSE 3 END,
unix_timestamp desc;
The ORDER BY
clause represents the ranking.
Upvotes: 1
Reputation: 125214
select sum (amount), id
from (
select distinct on (billing_id) *
from (
select distinct on (status, billing_id) *
from invoice_records
where
id = $1
and time between '2017-06-01' and '2017-07-01'
and status in ('done', 'ongoing')
order by status, billing_id desc
) s
order by billing_id desc
) s
Upvotes: 0