找到满足两个不同聚合标准的记录的更好方法?
Better way to find records meeting two different aggregate criteria?
我需要找到贷方交易总和大于或等于阈值金额并且借方交易总和小于或等于该阈值的倒数的客户相同的门槛金额。我还想 return 总交易金额满足信用和借记阈值的交易。我想出了两个解决方案,但我认为我可能会使事情变得比必要的更复杂。
这是一些简化的示例数据...
TransactionID CustomerID TransactionDate TransactionType TransactionAmount
------------- ---------- --------------- --------------- -----------------
1 1 2020-10-01 Credit 10.25
2 1 2020-10-02 Credit 11.50
3 1 2020-10-02 Debit -13.25
4 2 2020-10-01 Credit 14.22
5 2 2020-10-02 Debit -50.75
6 2 2020-10-04 Credit 12.85
7 2 2020-10-07 Debit -4.53
8 3 2020-10-02 Credit 12.85
门槛金额为 20 美元 CustomerID 2 是唯一同时满足贷方和借方门槛的客户。所以这是我的预期结果...
TransactionID CustomerID TransactionDate TransactionType TransactionAmount
------------- ---------- --------------- --------------- -----------------
4 2 2020-10-01 Credit 14.22
6 2 2020-10-04 Credit 12.85
5 2 2020-10-02 Debit -50.75
7 2 2020-10-07 Debit -4.53
我想出了两个解决方案。我应该提到,由于我最终需要在其中嵌入此查询的软件,我无法使用临时 tables 或 table 变量。
解决方案#1
SELECT
txn.TransactionID
, txn.CustomerID
, txn.TransactionDate
, txn.TransactionType
, txn.TransactionAmount
FROM Transactions txn
WHERE EXISTS (
SELECT
txn1.CustomerID
, SUM(txn1.TransactionAmount) AS [TransactionAmoutTotal]
FROM Transactions txn1
WHERE txn1.TransactionType = 'Credit'
AND txn1.CustomerID = txn.CustomerID
GROUP BY txn1.CustomerID
HAVING SUM(txn1.TransactionAmount) >= @ThresholdAmount
)
AND EXISTS (
SELECT
txn2.CustomerID
, SUM(txn2.TransactionAmount) AS [TransactionAmoutTotal]
FROM Transactions txn2
WHERE txn2.TransactionType = 'Debit'
AND txn2.CustomerID = txn.CustomerID
GROUP BY txn2.CustomerID
HAVING SUM(txn2.TransactionAmount) <= (@ThresholdAmount * -1)
)
ORDER BY txn.CustomerID
, txn.TransactionType
, txn.TransactionDate;
解决方案 #2
WITH txn_cte (TransactionID, CustomerID, TransactionDate, TransactionType, TransactionAmount, TransactionAmountTotal) AS
(
SELECT
txn.TransactionID
, txn.CustomerID
, txn.TransactionDate
, txn.TransactionType
, txn.TransactionAmount
, txn.TransactionAmountTotal
FROM (
SELECT
TransactionID
, CustomerID
, TransactionDate
, TransactionType
, TransactionAmount
, SUM(TransactionAmount) OVER (PARTITION BY CustomerID, TransactionType) AS [TransactionAmountTotal]
FROM Transactions
) txn
WHERE ABS(txn.TransactionAmountTotal) >= @ThresholdAmount
)
SELECT
txn_cte.TransactionID
, txn_cte.CustomerID
, txn_cte.TransactionDate
, txn_cte.TransactionType
, txn_cte.TransactionAmount
FROM txn_cte
WHERE EXISTS (
SELECT txn_cte1.TransactionID
FROM txn_cte txn_cte1
WHERE txn_cte1.TransactionType = 'Credit'
AND txn_cte1.CustomerID = txn_cte.CustomerID
)
AND EXISTS (
SELECT txn_cte2.TransactionID
FROM txn_cte txn_cte2
WHERE txn_cte2.TransactionType = 'Debit'
AND txn_cte2.CustomerID = txn_cte.CustomerID
)
ORDER BY txn_cte.CustomerID
, txn_cte.TransactionType
, txn_cte.TransactionDate;
这是我的示例数据插入的 dbfiddle 和两个解决方案。鉴于我不能使用 temp tables 或 table 变量,有没有更好的方法来做到这一点?
您可以使用 window 函数:
select transactionid, customerid, transactiondate, transactiontype, transactionamount
from (
select t.*,
sum(case when transactiontype = 'Credit' then transactionamount else 0 end)
over(partition by customerid) sum_credit,
sum(case when transactiontype = 'Debit' then transactionamount else 0 end)
over(partition by customerid) sum_debit
from transactions t
) t
where sum_credit > @ThresholdAmount and sum_debit < - @ThresholdAmount
order by customerid, transactiontype, transactiondate
在子查询中,条件总和计算每个客户的总借方和贷方。然后您可以使用此信息在外部查询中进行过滤。
也许 HAVING
中的某些条件聚合是您所追求的?虽然这 returns 没有行,因为没有客户有 “大于阈值金额的贷方交易总和以及大于同一阈值金额的借方交易总和”。那是因为所有借记交易都有负值,负值的 SUM
永远不会是正数(因此永远不会大于示例中的 20
的值):
DECLARE @ThresholdAmount NUMERIC(10, 2);
SET @ThresholdAmount = 20.00;
SELECT CustomerID
FROM dbo.Transactions
GROUP BY CustomerID
HAVING SUM(CASE TransactionType WHEN 'Credit' THEN TransactionAmount END) > @ThresholdAmount
AND SUM(CASE TransactionType WHEN 'Debit' THEN TransactionAmount END) > @ThresholdAmount;
我需要找到贷方交易总和大于或等于阈值金额并且借方交易总和小于或等于该阈值的倒数的客户相同的门槛金额。我还想 return 总交易金额满足信用和借记阈值的交易。我想出了两个解决方案,但我认为我可能会使事情变得比必要的更复杂。
这是一些简化的示例数据...
TransactionID CustomerID TransactionDate TransactionType TransactionAmount
------------- ---------- --------------- --------------- -----------------
1 1 2020-10-01 Credit 10.25
2 1 2020-10-02 Credit 11.50
3 1 2020-10-02 Debit -13.25
4 2 2020-10-01 Credit 14.22
5 2 2020-10-02 Debit -50.75
6 2 2020-10-04 Credit 12.85
7 2 2020-10-07 Debit -4.53
8 3 2020-10-02 Credit 12.85
门槛金额为 20 美元 CustomerID 2 是唯一同时满足贷方和借方门槛的客户。所以这是我的预期结果...
TransactionID CustomerID TransactionDate TransactionType TransactionAmount
------------- ---------- --------------- --------------- -----------------
4 2 2020-10-01 Credit 14.22
6 2 2020-10-04 Credit 12.85
5 2 2020-10-02 Debit -50.75
7 2 2020-10-07 Debit -4.53
我想出了两个解决方案。我应该提到,由于我最终需要在其中嵌入此查询的软件,我无法使用临时 tables 或 table 变量。
解决方案#1
SELECT
txn.TransactionID
, txn.CustomerID
, txn.TransactionDate
, txn.TransactionType
, txn.TransactionAmount
FROM Transactions txn
WHERE EXISTS (
SELECT
txn1.CustomerID
, SUM(txn1.TransactionAmount) AS [TransactionAmoutTotal]
FROM Transactions txn1
WHERE txn1.TransactionType = 'Credit'
AND txn1.CustomerID = txn.CustomerID
GROUP BY txn1.CustomerID
HAVING SUM(txn1.TransactionAmount) >= @ThresholdAmount
)
AND EXISTS (
SELECT
txn2.CustomerID
, SUM(txn2.TransactionAmount) AS [TransactionAmoutTotal]
FROM Transactions txn2
WHERE txn2.TransactionType = 'Debit'
AND txn2.CustomerID = txn.CustomerID
GROUP BY txn2.CustomerID
HAVING SUM(txn2.TransactionAmount) <= (@ThresholdAmount * -1)
)
ORDER BY txn.CustomerID
, txn.TransactionType
, txn.TransactionDate;
解决方案 #2
WITH txn_cte (TransactionID, CustomerID, TransactionDate, TransactionType, TransactionAmount, TransactionAmountTotal) AS
(
SELECT
txn.TransactionID
, txn.CustomerID
, txn.TransactionDate
, txn.TransactionType
, txn.TransactionAmount
, txn.TransactionAmountTotal
FROM (
SELECT
TransactionID
, CustomerID
, TransactionDate
, TransactionType
, TransactionAmount
, SUM(TransactionAmount) OVER (PARTITION BY CustomerID, TransactionType) AS [TransactionAmountTotal]
FROM Transactions
) txn
WHERE ABS(txn.TransactionAmountTotal) >= @ThresholdAmount
)
SELECT
txn_cte.TransactionID
, txn_cte.CustomerID
, txn_cte.TransactionDate
, txn_cte.TransactionType
, txn_cte.TransactionAmount
FROM txn_cte
WHERE EXISTS (
SELECT txn_cte1.TransactionID
FROM txn_cte txn_cte1
WHERE txn_cte1.TransactionType = 'Credit'
AND txn_cte1.CustomerID = txn_cte.CustomerID
)
AND EXISTS (
SELECT txn_cte2.TransactionID
FROM txn_cte txn_cte2
WHERE txn_cte2.TransactionType = 'Debit'
AND txn_cte2.CustomerID = txn_cte.CustomerID
)
ORDER BY txn_cte.CustomerID
, txn_cte.TransactionType
, txn_cte.TransactionDate;
这是我的示例数据插入的 dbfiddle 和两个解决方案。鉴于我不能使用 temp tables 或 table 变量,有没有更好的方法来做到这一点?
您可以使用 window 函数:
select transactionid, customerid, transactiondate, transactiontype, transactionamount
from (
select t.*,
sum(case when transactiontype = 'Credit' then transactionamount else 0 end)
over(partition by customerid) sum_credit,
sum(case when transactiontype = 'Debit' then transactionamount else 0 end)
over(partition by customerid) sum_debit
from transactions t
) t
where sum_credit > @ThresholdAmount and sum_debit < - @ThresholdAmount
order by customerid, transactiontype, transactiondate
在子查询中,条件总和计算每个客户的总借方和贷方。然后您可以使用此信息在外部查询中进行过滤。
也许 HAVING
中的某些条件聚合是您所追求的?虽然这 returns 没有行,因为没有客户有 “大于阈值金额的贷方交易总和以及大于同一阈值金额的借方交易总和”。那是因为所有借记交易都有负值,负值的 SUM
永远不会是正数(因此永远不会大于示例中的 20
的值):
DECLARE @ThresholdAmount NUMERIC(10, 2);
SET @ThresholdAmount = 20.00;
SELECT CustomerID
FROM dbo.Transactions
GROUP BY CustomerID
HAVING SUM(CASE TransactionType WHEN 'Credit' THEN TransactionAmount END) > @ThresholdAmount
AND SUM(CASE TransactionType WHEN 'Debit' THEN TransactionAmount END) > @ThresholdAmount;