运行 每次列值更改时更改的总数

Running Total That Changes Each Time A Column Value Changes

早上好。

我正在尝试解决一个与下面的 post 非常相似的问题,但有 1 个额外的参数让我感到困惑。

SQL Server Query, running total in view, reset when column A changes

在这个问题的回答中,提供了下面的代码。

原码

DECLARE @T TABLE (Category VARCHAR(5), Value INT)
INSERT INTO @T VALUES 
    ('Cat A', 10),
    ('Cat A', 20),
    ('Cat A', 30),
    ('Cat B', 15),
    ('Cat B', 15),
    ('Cat C', 10),
    ('Cat C', 10)

;WITH T AS
(   SELECT  Category, Value, ROW_NUMBER() OVER(PARTITION BY Category ORDER BY Value) [RowNumber]
    FROM    @T
)
SELECT  T1.Category,
        T1.Value,
        RunningTotal
FROM    T T1
        OUTER APPLY
        (   SELECT  SUM(Value) [RunningTotal]
            FROM    T T2
            WHERE   T2.Category = T1.Category
            AND     T2.RowNumber <= T1.RowNumber
        ) RunningTotal

如果类别应该按顺序排列,则此解决方案可以正常工作;但是,例如,如果顺序为 A、A、A、B、B、C、C、A、A、B,则所有 A 将在顶部分组,然后是 B,等等,并且不会保留顺序。这可以在下面看到:

扩展示例

DECLARE @T TABLE (Category VARCHAR(5), Value INT)
INSERT INTO @T VALUES 
    ('Cat A', 10),
    ('Cat A', 20),
    ('Cat A', 30),
    ('Cat B', 15),
    ('Cat B', 15),
    ('Cat C', 10),
    ('Cat C', 10),
    ('Cat A', 100),
    ('Cat A', 05),
    ('Cat B', 15)

;WITH T AS
(   SELECT  Category, Value, ROW_NUMBER() OVER(PARTITION BY Category ORDER BY Value) [RowNumber]
    FROM    @T
)
SELECT  T1.Category,
        T1.Value,
        RunningTotal
FROM    T T1
        OUTER APPLY
        (   SELECT  SUM(Value) [RunningTotal]
            FROM    T T2
            WHERE   T2.Category = T1.Category
            AND     T2.RowNumber <= T1.RowNumber
        ) RunningTotal

示例代码输出

╔══════════╦════════╦═══════════════╗
║ Category ║ Amount ║ Running Total ║
╠══════════╬════════╬═══════════════╣
║ Cat A    ║      5 ║             5 ║
║ Cat A    ║     10 ║            15 ║
║ Cat A    ║     20 ║            35 ║
║ Cat A    ║     30 ║            65 ║
║ Cat A    ║    100 ║           165 ║
║ Cat B    ║     15 ║            15 ║
║ Cat B    ║     15 ║            30 ║
║ Cat B    ║     15 ║            45 ║
║ Cat C    ║     10 ║            10 ║
║ Cat C    ║     10 ║            20 ║
╚══════════╩════════╩═══════════════╝

需要输出

我又添加了一列来说明我的示例。如下所示,table 按日期排序,因此类别保持该顺序;但是,每次类别更改时,运行 总数都会重置。

╔══════════╦════════╦═══════════════╦════════════╗
║ Category ║ Amount ║ Running Total ║    Date    ║
╠══════════╬════════╬═══════════════╬════════════╣
║ Cat A    ║     10 ║            10 ║ 23/10/2015 ║
║ Cat A    ║     20 ║            30 ║ 17/10/2015 ║
║ Cat A    ║     30 ║            60 ║ 15/10/2015 ║
║ Cat B    ║     15 ║            15 ║ 02/10/2015 ║
║ Cat B    ║     15 ║            30 ║ 24/09/2015 ║
║ Cat C    ║     10 ║            10 ║ 17/09/2015 ║
║ Cat C    ║     10 ║            20 ║ 14/09/2015 ║
║ Cat A    ║    100 ║           100 ║ 12/09/2015 ║
║ Cat A    ║      5 ║           105 ║ 08/09/2015 ║
║ Cat B    ║     15 ║            15 ║ 03/09/2015 ║
╚══════════╩════════╩═══════════════╩════════════╝

日期相同的示例

请注意,前 2 个条目的日期相同。

╔══════════╦═══════╦════════════╦══════════════╗
║ Category ║ Value ║    Date    ║ RunningTotal ║
╠══════════╬═══════╬════════════╬══════════════╣
║ Cat A    ║    10 ║ 30/05/2015 ║           30 ║
║ Cat A    ║    20 ║ 30/05/2015 ║           30 ║
║ Cat A    ║    30 ║ 28/05/2015 ║           60 ║
║ Cat B    ║    15 ║ 27/05/2015 ║           15 ║
║ Cat B    ║    15 ║ 26/05/2015 ║           30 ║
║ Cat C    ║    10 ║ 25/05/2015 ║           10 ║
║ Cat C    ║    10 ║ 24/05/2015 ║           20 ║
║ Cat A    ║   100 ║ 23/05/2015 ║          100 ║
║ Cat A    ║     5 ║ 22/05/2015 ║          105 ║
║ Cat B    ║    15 ║ 21/05/2015 ║           15 ║
╚══════════╩═══════╩════════════╩══════════════╝

类别的数量可以更改,最多可以有 100 个不同的值。

此查询将在 SSRS 报告中使用,因此如果有人可以帮助我提供 SSRS 示例,那就太好了,否则 SQL 也很棒。

非常感谢,

忍者。

这是一个例子。首先你得到岛屿,然后计算 运行 总数:

DECLARE @T TABLE (Category VARCHAR(5), Value INT, Date DATE)
INSERT INTO @T VALUES 
    ('Cat A', 10, '20150530'),
    ('Cat A', 20, '20150529'),
    ('Cat A', 30, '20150528'),
    ('Cat B', 15, '20150527'),
    ('Cat B', 15, '20150526'),
    ('Cat C', 10, '20150525'),
    ('Cat C', 10, '20150524'),
    ('Cat A', 100, '20150523'),
    ('Cat A', 05, '20150522'),
    ('Cat B', 15, '20150521')

;WITH cte AS(SELECT *, ROW_NUMBER() OVER(Order By date DESC)
              - ROW_NUMBER() OVER(Partition By Category Order By date DESC) rn FROM @t)
SELECT * FROM cte c1
CROSS APPLY(SELECT SUM(c2.Value) AS RunningTotal FROM cte c2 
            WHERE c2.rn = c1.rn AND c2.Category = c1.Category AND c2.Date >= c1.Date) ca
ORDER BY c1.Date desc

输出:

Category    Value   Date        rn  RunningTotal
Cat A       10      2015-05-30  0   10
Cat A       20      2015-05-29  0   30
Cat A       30      2015-05-28  0   60
Cat B       15      2015-05-27  3   15
Cat B       15      2015-05-26  3   30
Cat C       10      2015-05-25  5   10
Cat C       10      2015-05-24  5   20
Cat A       100     2015-05-23  4   100
Cat A       5       2015-05-22  4   105
Cat B       15      2015-05-21  7   15

编辑:

只需在上面添加另一个 cte 即可给出明确的排序:

;WITH cte1 AS(SELECT *, ROW_NUMBER() OVER(Order By date DESC) rn1 FROM @T),
      cte2 AS(SELECT *, ROW_NUMBER() OVER(Order By rn1)
              - ROW_NUMBER() OVER(Partition By Category Order By rn1) rn2 FROM cte1)
SELECT * FROM cte2 c1
CROSS APPLY(SELECT SUM(c2.Value) AS RunningTotal FROM cte2 c2 
            WHERE c2.rn2 = c1.rn2 AND c2.Category = c1.Category AND c2.rn1 <= c1.rn1) ca
ORDER BY c1.Date desc