2016-08-12 23 views
0

我有一個模式,它看起來像以下:如何通過比較子表上沒有子查詢的兩個總和來選擇行?

Invoices:  | id | ... | 
InvoicePayments: | id | invoice_id | amount_cents | ... | 
LineItems:  | id | invoice_id | unit_price_cents | quantity | ... | 

,我期待找到未付發票,也就是說,誰擁有amount_cents的總和從InvoicePayments小於(數量的總和發票* unit_price)來自LineItems。我能夠用兩個子查詢做到這一點,如:

SELECT prices.id FROM (
    SELECT invoices.id, sum(invoice_payments.amount_cents) as paid 
    FROM invoices 
    LEFT JOIN invoice_payments ON invoice_payments.invoice_id = invoices.id 
    GROUP BY invoices.id 
) payments JOIN (
    SELECT invoices.id, sum(line_items.quantity * line_items.unit_price_cents) as price 
    FROM invoices 
    LEFT JOIN line_items ON line_items.invoice_id = invoices.id 
    GROUP BY invoices.id 
) prices 
ON payments.id = prices.id 
WHERE paid < price OR paid IS NULL; 

不過,我使用ActiveRecord,想簡單的東西,可轉化成阿雷爾報表;此外,我希望將此用作可重用範圍,因此可以通過篩選出比該日期更新的InvoicePayments來應用其他約束,例如查找在某個日期未付的發票。

是否有一種方法可以在沒有子查詢的情況下完成此操作,以便我可以更輕鬆地使用Rails並應用靈活的過濾器?

回答

0

一種方法是定義視圖來封裝上面定義的子查詢,然後在其上定義只讀模型。

然後,他們可以與發票模型相關聯,併爲您提供了大量簡化語法的機會。

0
SELECT 
    i.id 
    COALESCE(SUM(l.quantity * l.unit_price_cents),0) - COALESCE(SUM(p.amounts_cents),0) as UnpaidBalance 
FROM 
    invoices i 
    LEFT JOIN invoice_payments p 
    ON i.id = p.invoice_id 
    AND p.DateColumn <= '2016-01-30' 
    LEFT JOIN line_items l 
    ON i.id = l.invoice_id 
GROUP BY 
    i.id 
HAVING 
    COALESCE(SUM(p.amounts_cents),0) < COALESCE(SUM(l.quantity * l.unit_price_cents),0) 

特別是隨着加窗函數對許多關係型數據庫管理系統,如PostgreSQL,你很少需要這樣的子查詢了。在使用左連接時,集合函數將忽略空值,因此只需將左連接組合到同一個查詢中,仍然可以獲得期望的結果。

您可能會注意到使用表別名,這使得它更容易閱讀,而且更少地爲您編寫代碼。你可以通過在你的查詢中的表名之後輸入一個來定義一個別名。我確實包括了p.DateColumn <= some date。你可以通過參數化查詢來傳遞一個變量,如果它是null,並且選擇當前的日期時間,如果你想從今天開始的話。