編輯:我已經加入另一個濾波器(HAVING
子句)只顯示那些completed
週期。
此解決方案使用遞歸CTE:
1)來計算運行總數(RunningTotal)爲每個項目和
2)來產生用於每一個項目週期的組ID(PseudoDenseRank)。
CREATE TABLE [Transaction]
(
TransactionId INT IDENTITY(10,10) PRIMARY KEY
,Item VARCHAR(100) NOT NULL
,TransactionType CHAR(1) NOT NULL
,Qty INT NOT NULL
,TransactionDate DATE NOT NULL
,CHECK(TransactionType IN ('B', 'S')) --Buy, Sell
);
INSERT [Transaction]
SELECT 'apple', 'B', 1, '2010-01-01'
UNION ALL
SELECT 'apple', 'B', 1, '2010-01-02'
UNION ALL
SELECT 'orange','B', 1, '2010-01-03'
UNION ALL
SELECT 'apple', 'S', 1, '2010-01-03'
UNION ALL
SELECT 'apple', 'S', 1, '2010-01-20'
UNION ALL
SELECT 'orange','S', 1, '2010-01-22'
UNION ALL
SELECT 'apple', 'B', 2, '2010-02-01'
UNION ALL
SELECT 'orange','B', 3, '2010-02-02'
UNION ALL
SELECT 'apple', 'S', 1, '2010-02-03'
UNION ALL
SELECT 'apple', 'S', 1, '2010-02-10'
UNION ALL
SELECT 'orange','S', 1, '2010-02-10'
UNION ALL
SELECT 'orange','S', 1, '2010-02-11';
DECLARE @Results TABLE
(
TransactionId INT NOT NULL
,Item VARCHAR(100) NOT NULL
,TransactionType CHAR(1) NOT NULL
,Qty INT NOT NULL
,TransactionDate DATE NOT NULL
,RowNum INT NOT NULL
,PRIMARY KEY (Item, RowNum)
);
INSERT @Results
SELECT *
,ROW_NUMBER() OVER(PARTITION BY t.Item ORDER BY t.TransactionDate ASC, t.TransactionType ASC, t.TransactionId ASC) RowNum
FROM [Transaction] t;
WITH CteRecursive
AS
(
SELECT q.Item
,q.RowNum
,CASE WHEN q.TransactionType = 'B' THEN q.Qty END QtyBuy
,CASE WHEN q.TransactionType = 'S' THEN q.Qty END QtySell
,q.TransactionDate
,CASE WHEN q.TransactionType = 'B' THEN q.Qty WHEN q.TransactionType = 'S' THEN -q.Qty END AS RunningTotal
,1 AS PseudoDenseRank
FROM @Results q
WHERE q.RowNum = 1
UNION ALL
SELECT prev.Item
,crt.RowNum
,CASE WHEN crt.TransactionType = 'B' THEN crt.Qty END QtyBuy
,CASE WHEN crt.TransactionType = 'S' THEN crt.Qty END QtySell
,crt.TransactionDate
,prev.RunningTotal + CASE WHEN crt.TransactionType = 'B' THEN crt.Qty WHEN crt.TransactionType = 'S' THEN -crt.Qty END
,CASE WHEN prev.RunningTotal = 0 THEN prev.PseudoDenseRank + 1 ELSE prev.PseudoDenseRank END
FROM CteRecursive prev
INNER JOIN @Results crt ON prev.Item = crt.Item
AND prev.RowNum + 1 = crt.RowNum
)
SELECT q.Item
,q.PseudoDenseRank AS CycleNumber
,SUM(q.QtyBuy) AS QtyBuyTotal
,SUM(q.QtySell) AS QtySellTotal
,CASE WHEN ISNULL(SUM(q.QtyBuy), 0) - ISNULL(SUM(q.QtySell),0) = 0 THEN 'Complete' ELSE 'Incomplete' END AS CycleStatus
,MIN(q.TransactionDate) AS CycleStartDate
,MAX(q.TransactionDate) AS CycleEndDate
,CONVERT(VARCHAR(25), MIN(q.TransactionDate), 112) + ' - ' + CONVERT(VARCHAR(25), MAX(q.TransactionDate), 112) AS CycleInterval
FROM CteRecursive q
GROUP BY q.Item, q.PseudoDenseRank
HAVING ISNULL(SUM(q.QtyBuy), 0) - ISNULL(SUM(q.QtySell),0) = 0
ORDER BY q.Item, q.PseudoDenseRank;
DROP TABLE [Transaction];
結果:
Item CycleNumber QtyBuyTotal QtySellTotal CycleStatus CycleStartDate CycleEndDate CycleInterval
------ ----------- ----------- ------------ ----------- -------------- ------------ -----------------------
apple 1 2 2 Complete 2010-01-01 2010-01-20 2010-01-01 - 2010-01-20
apple 2 2 2 Complete 2010-02-01 2010-02-10 2010-02-01 - 2010-02-10
orange 1 1 1 Complete 2010-01-03 2010-01-22 2010-01-03 - 2010-01-22
--The next row is eliminated by the filter from HAVING
orange 2 3 2 Incomplete 2010-02-02 2010-02-11 2010-02-02 - 2010-02-11
*「這不會出現在列表中」 * - 正是將不會出現在列表中,第三個蘋果或整個'apple'行? –