You need a single row per invoice, so aggregate payment_invoice
first - best before you join.
When the whole table is selected, it's typically fastest to aggregate first and join later:
SELECT to_char(date_trunc('month', i.create_datetime), 'MM/YYYY') AS month
, count(*) AS total_invoice_count
, (sum(i.total) - COALESCE(sum(pi.paid), 0)) AS outstanding_balance
FROM invoice i
LEFT JOIN (
SELECT invoice_id AS id, sum(amount) AS paid
FROM payment_invoice pi
GROUP BY 1
) pi USING (id)
GROUP BY date_trunc('month', i.create_datetime)
ORDER BY date_trunc('month', i.create_datetime);
LEFT JOIN
is essential here. You do not want to loose invoices that have no corresponding rows in payment_invoice
(yet), which would happen with a plain JOIN
.
Accordingly, use COALESCE()
for the sum of payments, which might be NULL.
SQL Fiddle with improved test case.