我有这个查询,总结付款和报销的承诺。它有效,但闻起来很糟糕:
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
特别是,我认为应该有更好的方法来处理joins
内的joins
,特别是因为它们会产生相同的结果。在另一个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 :(得分:0)
查询应选择所有承诺(他们的pledgeID
和decamount
)以及每个承诺的付款总额。有些付款是积极的,有些是负面的。
您查询选择所有承诺,将正付款加入每个承诺,并将负付款加入与承诺相关的每一行。如果最多只有一个负数且最多一个正数,那么它几乎可以正常工作(除非它没有付款时返回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()
,那么就会发出decamount
电话。 COALESCE()
内SUM()
到{0}总是可以安全地省略,因为SUM()
会跳过NULL;我猜这些调用只是在原始查询中破解连接的角落情况的工件。