更新行链,其中每一行将通过计算列影响下一行

问题描述 投票:0回答:1

假设这张表:

CREATE TABLE Operation (
    Id int PRIMARY KEY,
    Change int,
    PreviousId int null FOREIGN KEY REFERENCES Operation(id),
    PreviousAmount int null,
    NewAmount AS (COALESCE(PreviousAmount,0) + Change) PERSISTED
);

有了这些数据:

INSERT INTO Operation (Id, Change, PreviousId, PreviousAmount)
VALUES
(1, 1, null, null),
(2, 2, 1, 1),
(3, 3, 2, 3),
(4, 4, 3, 5);

到目前为止 PreviousAmount 和 NewAmount 有有效数据:

id  change  previousId  previousAmount  newAmount
-------------------------------------------------
1   1       NULL        NULL            1
2   2       1           1               3
3   3       2           3               6
4   4       3           5               9 

假设我们更新第一行“change”:

Update Operation set Change=10 where id=1

我想要一个触发器来更新行链中的所有 PreviousAmount,以便每一行在其“PreviousAmount”内保存上一行更新的“NewAmount”

sql sql-server t-sql recursive-query
1个回答
0
投票

仅给出原始 idchange 列,您可以使用 窗口函数

LAG()
SUM()
来选择 previousIdpreviousAmountnewAmount 值。

窗口

SUM()
函数(具有
OVER()
限定符)通常会为您提供当前行的运行总计,但可以通过向
ROWS
添加
OVER()
规范来调整此范围,以产生通过前一行运行总和。

结果查询将是:

SELECT
   D.id,
   D.change,
   LAG(id) OVER(ORDER BY id) AS previousId,
   SUM(change) OVER(
        ORDER BY id
        ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
        ) AS PreviousAmount,
   SUM(change) OVER(ORDER BY id) AS NewAmount
FROM Data D
ORDER BY D.id

如果(反对所有建议)您确实想将这些结果存储回表中,您可以运行以下

UPDATE
语句:

UPDATE D
SET
    previousId = previousIdCalc,
    previousAmount = previousAmountCalc,
    newAmount = newAmountCalc
FROM (
    SELECT
        D.*,
        LAG(id) OVER(ORDER BY id) AS previousIdCalc,
        SUM(change) OVER(
             ORDER BY id
             ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
             ) AS previousAmountCalc,
        SUM(change) OVER(ORDER BY id) AS newAmountCalc
    FROM Data D
) D

请参阅 this db<>fiddle 以获取选择和更新的演示。

结果:

id 改变 上一个ID 上一页金额 新金额
1 1 1
2 2 1 1 3
3 3 2 3 6
4 4 3 6 10
© www.soinside.com 2019 - 2024. All rights reserved.