2017-08-25 37 views
-1

我有這個查詢,它將對支付和償還進行抵押。它的工作原理,但味道不好:在MySQL中沒有CTE有效地連接兩次相同的數據?

select P.pledgeID, P.decamount, 
(
    sum(coalesce(C1.decamount, 0)) - sum(coalesce(C2.decamount, 0)) 
) as paymentTotal 
from Pledge P 
left join (select C.*, CT.eaddOrSubtract 
      from `Payment` C 
      left join PaymentType CT on C.paymentTypeID = CT.paymentTypeID) 
     C1 on P.pledgeID = C1.pledgeID and C1.eaddOrSubtract = 'add' 
left join (select C.*, CT.eaddOrSubtract 
      from `Payment` C 
      left join PaymentType CT on C.paymentTypeID = CT.paymentTypeID) 
     C2 on P.pledgeID = C2.pledgeID and C2.eaddOrSubtract = 'subtract' 
group by pledgeID 

特別,我覺得應該有更好的方式來處理joinsjoins,特別是因爲它們產生相同的結果。在另一個RDBMS上,我會使用CTE,但在這裏不可用。有沒有更有效的方法來計算這些支付總額(考慮到一些是淨增加和其他淨減法的事實)?

架構信息:

PaymentType 
--- 
| paymentTypeID | eaddOrSubtract | ... 
| 1    | add   | 
| 2    | add   | 
| 3    | subtract  | 
| 4    | add   | 
| 5    | subtract  | 



Payment 
--- 
| checkID | pledgeID | paymentTypeID | decamount | ... 
| 1  | 19415 | 4    | 15.19  | 
| 2  | 19414 | 2    | 900.00 | 
| 3  | 19106 | 5    | 3856.00 | 
| 4  | 19106 | 3    | 52.00  | 
| 5  | 19414 | 1    | 15.00  | 
+0

是否可以使用表變量?有了這些,你可以獲得更快的連接,因爲表變量完全在內存中。你甚至可以索引這些。 – kurdy

+0

請參閱:[爲什麼我應該爲我認爲是非常簡單的SQL查詢提供一個MCVE?](https://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve -for-what-seems-to-what-seem-a-very-simple-sql-query) – Strawberry

+0

「GROUP BY」子句中的列名應該更好地限定:「group by P.pledgeID」。它更清晰,例如SQLite要求。在MySQL中,它不是必需的,但它仍然更具可讀性。 – Palec

回答

0

查詢應選擇所有承諾(他們pledgeIDdecamount)和總的每個承諾支付的。一些付款是積極的,有些是負面的。

您查詢選擇所有質押,將正面支付加入每個質押並將負支付加入與質押相關的每一行。如果最多隻有一個負數,最多隻有一個正數付款,它幾乎可以工作(除非在沒有付款的情況下返回NULL而不是0)。一旦至少有兩種類型的付款(正面/負面)和至少一種類別出現,就會出現問題。每個負付款與同一個承諾中的每個正付款相結合,並且所有對都相加。

直接在這個答案的第一段,看一下這個問題的更簡潔的方法。代替在eaddOrSubtract上使用篩選器的兩個連接,只需將一個連接添加到子查詢中,其中子查詢在內部處理正在求和的數量的符號。 CASE operator非常適合這樣的工作。

SELECT 
    P.pledgeID 
, P.decamount 
, COALESCE(SUM(C.signedDecamount), 0) AS paymentTotal 
FROM Pledge P 
LEFT JOIN (
    SELECT 
    C.* 
    , CASE CT.eaddOrSubtract 
    WHEN 'add' THEN C.decamount 
    WHEN 'subtract' THEN -C.decamount 
    END AS signedDecamount 
    FROM Payment C 
    LEFT JOIN PaymentType CT ON C.paymentTypeID = CT.paymentTypeID 
) C ON P.pledgeID = C.pledgeID 
GROUP BY P.pledgeID 

COALESCE()調用那裏的情況下,在沒有付款加入到質押或所有他們加入支付有NULL decamountCOALESCE()爲0內部SUM()總是可以安全省略,因爲SUM()跳過NULL;我想這些調用只是黑客在原始查詢中加入角落的案例。

SQL Fiddle

相關問題