I have a business requirement to produce a running total, but with a twist ... If the running total drops below zero, then it resets to zero.In SQL 2008R2, I used a recursive CTE to get a running total[code="sql"]DECLARE @TranTable TABLE ( AccountID INT NOT NULL , TranDate DATETIME NOT NULL , TranValue DECIMAL(18,2) NOT NULL);INSERT INTO @TranTable ( AccountID, TranDate, TranValue )VALUES ( 1, '2016/01/21 03:58:12', 23.05 ) , ( 1, '2016/01/23 11:02:15', 24.05 ) , ( 1, '2016/02/14 14:08:13',-40.00 ) , ( 1, '2016/02/16 07:25:08', 25.00 ) , ( 1, '2016/03/17 23:18:25', 25.05 ) --------------------------------------- , ( 2, '2016/01/21 03:58:12', 23.05 ) , ( 2, '2016/01/23 11:02:15', 24.05 ) , ( 2, '2016/02/14 14:08:13',-50.00 ) , ( 2, '2016/02/16 07:25:08', 25.00 ) , ( 2, '2016/03/17 23:18:25', 25.05 ) --------------------------------------- , ( 3, '2016/01/21 03:58:12', 23.05 ) , ( 3, '2016/01/23 11:02:15',-30.00 ) , ( 3, '2016/02/14 14:08:13', 24.05 ) , ( 3, '2016/02/16 07:25:08',-30.00 ) , ( 3, '2016/03/17 23:18:25', 25.05 ) , ( 3, '2016/03/19 06:03:17', 12.50 );;WITH cteBaseData AS ( SELECT AccountID, TranDate, TranValue = CAST(TranValue AS DECIMAL(18,2)) , seq = ROW_NUMBER() OVER (PARTITION BY AccountID ORDER BY TranDate) FROM @TranTable), cteRecurs AS ( SELECT AccountID, TranDate, TranValue, seq , runTot = CAST(TranValue AS DECIMAL(18,2)) FROM cteBaseData WHERE seq = 1 UNION ALL SELECT cte1.AccountID, cte1.TranDate, cte1.TranValue, cte1.seq , runTot = CAST(CASE WHEN cte2.runTot + ISNULL(cte1.TranValue, 0.0) < 0 THEN 0 ELSE cte2.runTot + ISNULL(cte1.TranValue, 0.0) END AS DECIMAL(18,2)) FROM cteBaseData AS cte1 INNER JOIN cteRecurs AS cte2 ON cte1.AccountID = cte2.AccountID AND cte1.seq = cte2.seq + 1)SELECT AccountID, TranDate, TranValue, runTotFROM cteRecursORDER BY AccountID, TranDateOPTION (MAXRECURSION 10000);[/code]In SQL 2014, I would like to try and do the same using a window function. However, the reset part is giving me a headache.[code="sql"]DECLARE @TranTable TABLE ( AccountID INT NOT NULL , TranDate DATETIME NOT NULL , TranValue DECIMAL(18,2) NOT NULL);INSERT INTO @TranTable ( AccountID, TranDate, TranValue )VALUES ( 1, '2016/01/21 03:58:12', 23.05 ) , ( 1, '2016/01/23 11:02:15', 24.05 ) , ( 1, '2016/02/14 14:08:13',-40.00 ) , ( 1, '2016/02/16 07:25:08', 25.00 ) , ( 1, '2016/03/17 23:18:25', 25.05 ) --------------------------------------- , ( 2, '2016/01/21 03:58:12', 23.05 ) , ( 2, '2016/01/23 11:02:15', 24.05 ) , ( 2, '2016/02/14 14:08:13',-50.00 ) , ( 2, '2016/02/16 07:25:08', 25.00 ) , ( 2, '2016/03/17 23:18:25', 25.05 ) --------------------------------------- , ( 3, '2016/01/21 03:58:12', 23.05 ) , ( 3, '2016/01/23 11:02:15',-30.00 ) , ( 3, '2016/02/14 14:08:13', 24.05 ) , ( 3, '2016/02/16 07:25:08',-30.00 ) , ( 3, '2016/03/17 23:18:25', 25.05 ) , ( 3, '2016/03/19 06:03:17', 12.50 );SELECT AccountID, TranDate, TranValue , RunTot = SUM(TranValue) OVER (PARTITION BY AccountID ORDER BY TranDate ROWS UNBOUNDED PRECEDING) -------------------------------------------- -- The addition of the values in the case statement below, is to simulate the result that I am looking for , RunTot_Expected = SUM(TranValue) OVER (PARTITION BY AccountID ORDER BY TranDate ROWS UNBOUNDED PRECEDING) + CASE WHEN AccountID = 2 AND TranDate >= '2016-02-14 14:08:13' THEN 2.90 WHEN AccountID = 3 AND TranDate >= '2016-02-16 07:25:08' THEN 12.90 WHEN AccountID = 3 AND TranDate >= '2016-01-23 11:02:15' THEN 6.95 ELSE 0 END FROM @TranTableORDER BY AccountID, TranDate;[/code]Please note that I may not be able to access this board again until after the long weekend.
↧