【问题标题】:Recursively calculate total value of current row using previous row value SQL Server使用前一行值 SQL Server 递归计算当前行的总值
【发布时间】:2015-07-09 10:17:35
【问题描述】:

假设我有一张这样的桌子

 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

我想将总列更新为上一行的“总”值 + 当前行的 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 Server?您是否有任何明确的列要订购? id 的排序不是确定性的,因此不能用于确定地对行进行排序。
  • 我使用的是 SQL 2014。抱歉忘了提。
  • 好的,剩下第二个问题。我怎么知道 id=1 cardcount=1 应该在 id=1 cardcount=2 之前?是否有其他列决定行的顺序?

标签: sql-server tsql common-table-expression sql-server-2014


【解决方案1】:

如果您使用可以将聚合作为窗口函数的现代版本的 SQL Server,则不需要为此使用递归。然后你可以把sum()做为一个窗口函数:

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

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

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

【讨论】:

  • 这正是我所需要的。谢谢你。此处显示的表格只是我实际表格的简化版本,所以是的,我可以订购数据。
  • 如果您有东西要按派生表中的整个 row_number 对数据进行排序/分区,则可能会被删除。
猜你喜欢
  • 2016-01-10
  • 2021-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-30
  • 2021-05-29
相关资源
最近更新 更多