SQL 服务器累计突破

SQL Server Cumulative Sum breaks

我有一个金额字段,我想构建以下 table(CumulativeSum 和 GroupNo 列):

| Id | Amount | CumulativeSum | GroupNo |

| 1  | 1000   | 1000          | 0       |
| 2  | 2000   | 3000          | 0       |
| 3  | 1000   | 4000          | 0       |
| 4  | 3000   | 3000          | 1       |
| 5  | 2000   | 5000          | 1       |
| 6  | 3000   | 3000          | 2       |
| 7  | 1000   | 4000          | 2       |
| 8  | 4000   | 4000          | 3       |
| 9  | 2000   | 2000          | 4       |

注意:当 CumulativeSum 大于 5000 时,我需要它从 0 开始与新的组号 (GroupNo) 相加。

例如,第 1、2 和 3 行的总和等于 4000。第 4 行的数量为 3000,4000 + 3000 = 7000,它大于 5000,因此它必须中断并重新从 0 开始。

最简单的方法是使用递归 CTE。这些是有效的循环,其中下一个值是根据先前的值计算的。这是一个 link 的基本示例和它们如何工作的文章:https://www.sqlservertutorial.net/sql-server-basics/sql-server-recursive-cte/

在这种情况下,它检查以前的值+当前值是否超过5000;如果是,则重置计数器并将 GroupNo 加 1;否则它只是将当前值添加到 CumulativeSum。

CREATE TABLE #Amts (ID int PRIMARY KEY, Amount int);
INSERT INTO #Amts (ID, Amount)
VALUES
(1, 1000),    --  | 1000  | 0 |
(2, 2000),    --  | 3000  | 0 |
(3, 1000),    --  | 4000  | 0 |
(4, 3000),    --  | 3000  | 1 |
(5, 2000),    --  | 5000  | 1 |
(6, 3000),    --  | 3000  | 2 |
(7, 1000),    --  | 4000  | 2 |
(8, 4000),    --  | 4000  | 3 |
(9, 2000);    --  | 2000  | 4 |

WITH RunningTotals AS
    (SELECT A.ID, A.Amount, A.Amount AS CumulativeSum, 0 AS GroupNo
     FROM #Amts A
     WHERE ID = 1
     
     UNION ALL

     SELECT RT.ID + 1,
            A.Amount, 
            CASE WHEN RT.CumulativeSum + A.Amount > 5000 THEN A.Amount 
                ELSE RT.CumulativeSum + A.Amount END,
            CASE WHEN RT.CumulativeSum + A.Amount > 5000 THEN RT.GroupNo + 1
                ELSE RT.GroupNo END
     FROM RunningTotals RT
          INNER JOIN #Amts A ON RT.ID + 1 = A.ID
    )
SELECT  *
    FROM RunningTotals
    OPTION (MAXRECURSION 1000);

结果如下

ID  Amount  CumulativeSum  GroupNo
1   1000    1000           0
2   2000    3000           0
3   1000    4000           0
4   3000    3000           1
5   2000    5000           1
6   3000    3000           2
7   1000    4000           2
8   4000    4000           3
9   2000    2000           4

备注

  • 这目前要求 ID 是连续的并从 1 开始。如果不是,您可能需要使用 ROW_NUMBER() OVER (ORDER BY Id) 进行初始 CTE 以获得此
  • 我已经将 MAXRECURSION 1000 放在那里 - 这意味着它将执行此循环 1000 次。如果您的 table 比这个大,则需要增加该数字。

更新:修复了代码中的错误(RT.GroupNo + 1 在错误的位置)。还向输出添加了 'Amount' 列。