将一列中上一行的值添加到当前行的另一列

nif*_*gas 4 sql sql-server sql-server-2008

嗨,我在这样的表格中有一个专栏

Amount 
1
2
3
4
5
6
7
Run Code Online (Sandbox Code Playgroud)

我希望我的函数或存储过程的结果是这样的

output
--------

1
3
6
10
15
21
28
Run Code Online (Sandbox Code Playgroud)

针对上述专栏请帮我解决这方面的问题

Gar*_*thD 5

您可以使用OUTER APPLY:

CREATE TABLE #T (Amount INT);
INSERT #T (Amount) VALUES (1), (2), (3), (4), (5), (6), (7);

SELECT  T.Amount, T2.Amount
FROM    #T T
        OUTER APPLY
        (   SELECT  Amount = SUM(Amount)
            FROM    #T T2
            WHERE   T2.Amount <= T.Amount
        ) T2;

DROP TABLE #T;
Run Code Online (Sandbox Code Playgroud)

相关子查询:

CREATE TABLE #T (Amount INT);
INSERT #T (Amount) VALUES (1), (2), (3), (4), (5), (6), (7);

SELECT  T.Amount, 
        (   SELECT  Amount = SUM(Amount)
            FROM    #T T2
            WHERE   T2.Amount <= T.Amount
        ) 
FROM    #T T

DROP TABLE #T;
Run Code Online (Sandbox Code Playgroud)

两者都应该产生相同的计划(在这种情况下,它们基本相同,并且IO是相同的).


对,减法.最后到达那里,我将了解我最终如何得到解决方案,因为它花了我一段时间,它不像累积总和那么直接..

首先,我刚刚写出了一个与逻辑完全相同的查询,基本上:

f(x) = x - f(x - 1);
Run Code Online (Sandbox Code Playgroud)

因此,通过复制和粘贴上一行中的公式,我得到:

SELECT  [1] = 1,
        [2] = 2 - 1,
        [3] = 3 - (2 - 1),
        [4] = 4 - (3 - (2 - 1)),
        [5] = 5 - (4 - (3 - (2 - 1))),
        [6] = 6 - (5 - (4 - (3 - (2 - 1)))),
        [7] = 7 - (6 - (5 - (4 - (3 - (2 - 1)))));
Run Code Online (Sandbox Code Playgroud)

然后我扩展了所有的括号,给出:

SELECT  [1] = 1,
        [2] = 2 - 1,
        [3] = 3 - 2 + 1,
        [4] = 4 - 3 + 2 - 1,
        [5] = 5 - 4 + 3 - 2 + 1,
        [6] = 6 - 5 + 4 - 3 + 2 - 1,
        [7] = 7 - 6 + 5 - 4 + 3 - 2 + 1;
Run Code Online (Sandbox Code Playgroud)

正如可以看到的操作者交替+-每个量当你向下移动(即,对于5在添加3,6你减去3,然后进行7再次添加它).

这意味着您需要找出每个值的位置,以确定是否添加或减去它.所以用这个:

SELECT  T.Amount, 
        T2.RowNum,
        T2.Amount
FROM    #T T
        OUTER APPLY
        (   SELECT  Amount, RowNum = ROW_NUMBER() OVER(ORDER BY Amount DESC)
            FROM    #T T2
            WHERE   T2.Amount < T.Amount
        ) T2
WHERE   T.Amount IN (4, 5)
Run Code Online (Sandbox Code Playgroud)

你最终得到:

Amount  RowNum  Amount
-------------------------
4       1       3
4       2       2
4       3       1
-------------------------
5       1       4
5       2       3
5       3       2
5       4       1
Run Code Online (Sandbox Code Playgroud)

所以记住这两个的前一个formala:

[4] = 4 - 3 + 2 - 1,
[5] = 5 - 4 + 3 - 2 + 1,
Run Code Online (Sandbox Code Playgroud)

我们可以看到RowNum奇怪的地方我们需要 - 第二个数量,甚至我们需要添加它.我们不能在SUM函数中使用ROW_NUMBER(),因此我们需要执行第二个聚合,给出最终查询:

SELECT  T.Amount, 
        Subtraction = T.Amount - SUM(ISNULL(T2.Amount, 0))
FROM    #T T
        OUTER APPLY
        (   SELECT  Amount = CASE WHEN ROW_NUMBER() OVER(ORDER BY Amount DESC) % 2 = 0 THEN -Amount ELSE Amount END
            FROM    #T T2
            WHERE   T2.Amount < T.Amount
        ) T2
GROUP BY T.Amount;
Run Code Online (Sandbox Code Playgroud)

关于SQL小提琴的例子