我的实际表结构要复杂得多,但是下面是两个简化的表定义:
桌子 invoice
invoice
CREATE TABLE invoice ( id integer NOT NULL, create_datetime timestamp with time zone NOT NULL, total numeric(22,10) NOT NULL ); id create_datetime total ---------------------------- 100 2014-05-08 1000
桌子 payment_invoice
payment_invoice
CREATE TABLE payment_invoice ( invoice_id integer, amount numeric(22,10) ); invoice_id amount ------------------- 100 100 100 200 100 150
我想通过连接上述2个表来选择数据,并且所选数据应如下所示:-
month total_invoice_count outstanding_balance 05/2014 1 550
我正在使用的查询:
select to_char(date_trunc('month', i.create_datetime), 'MM/YYYY') as month, count(i.id) as total_invoice_count, (sum(i.total) - sum(pi.amount)) as outstanding_balance from invoice i join payment_invoice pi on i.id=pi.invoice_id group by date_trunc('month', i.create_datetime) order by date_trunc('month', i.create_datetime);
上面的查询给我错误的结果作为sum(i.total) - sum(pi.amount)回报(1000 + 1000 + 1000)-(100 + 200 + 150)= 2550 。 我希望它返回(1000)-(100 + 200 + 150)= 550
sum(i.total) - sum(pi.amount)
而且我无法将其更改为i.total - sum(pi.amount),因为这样我被迫将i.total列添加到group by子句中,而我不想这样做。
i.total - sum(pi.amount)
i.total
每个发票只需要一行,因此payment_invoice请先汇总-最好在加入之前。 选择整个表格后,通常最先进行汇总然后再_进行合并 的最快方法是:
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 在这里至关重要。您不希望丢失payment_invoice尚未在其中存在相应行的发票,而这会在Plain上发生JOIN。
LEFT JOIN
JOIN
相应地,将其COALESCE()用于付款总和,该总和可能为NULL。
COALESCE()
SQL Fiddle 具有改进的测试用例。