使用上一行值 SQL 服务器递归计算当前行的总值

Recursively calculate total value of current row using previous row value SQL Server

假设我有一个这样的table

 Id     Initial Value    CardCount  Total
 1      5                1          null
 1      0                2          null
 1      0                4          null
 2      10               0          null
 2      0                3          null
 2      0                1          null

并且我想将总计列更新为前一行的 "total" 值 + 当前行的 cardCount 的总和。对于每个 Id 中的第一条记录,总数是 InitialValue + CardCount。我希望结果是这样的:

 Id     Initial Value    CardCount  Total
 1      5                1          6
 1      0                2          8
 1      0                4          12
 2      10               0          10
 2      0                3          13
 2      0                1          14

我试过了,但结果不正确

declare @tmp Table(Id int, InitialValue int, CardCount int, total int null)
Insert into @tmp values (1, 5, 1, null)
Insert into @tmp values (1,  0, 2, null)
Insert into @tmp values (1,  0, 4, null)
Insert into @tmp values (2, 10, 0, null)
Insert into @tmp values (2,  0, 3, null)
Insert into @tmp values (2,  0, 1, null)

Update @tmp Set Total = InitialValue + CardCount

;with TmpTb as(
select 
    ROW_NUMBER() over (order by ID) RNum, * 
From 
    @tmp)

update c set Total= x.Total + CardCount
from TmpTb c join
(select a.RNum, a.ID, b.Total
From TmpTb a LEFT JOIN TmpTb b on a.RNum=b.RNum+1
where a.ID=b.ID )x on c.RNum>=x.RNum AND c.ID=x.ID

select * from @tmp

如果您使用的是 SQL 服务器的现代版本,它可以像 window 函数一样进行聚合,则不需要为此使用递归。然后你可以做 sum() 作为 window 函数:

update t1 set total = y.total
from (select *, rn = ROW_NUMBER() over (order by id) from @tmp) t1
join (
  select id, rn, sum(initialvalue+cardcount) over (partition by id order by rn) as total
  from (select *, rn = ROW_NUMBER() over (order by id) from @tmp) x
) y
on t1.rn = y.rn

使用您的示例数据,结果将是:

id  initialvalue    CardCount   total
1   5               1           6
1   0               2           8
1   0               4           12
2   10              0           10
2   0               3           13
2   0               1           14

这可能有效,也可能无效。此代码依赖于服务器每次都以相同的顺序返回行,这不是您可以依赖的,但是由于您的数据似乎没有任何东西可以确定顺序,这可能是您可以期望的最好的顺序。如果你想产生一个 运行 总数,你确实需要一个稳定的属性来以确定的方式对数据进行排序。

重点是,如果你不能对数据进行排序,你就无法确定地实现你想要的。