SQL - 顺序更新问题 - 使用更新数据进行更新

时间:2011-01-12 09:04:01

标签: sql sql-server-2005 tsql

考虑此表:

create table x (id int, total int, diff int)

这个数据:

[1, 100, 20]
[2, null, 30]
[3, null, -15]
[4, null, 4]
…

我需要计算"总数"根据前一行的列。

这意味着最终数据看起来应该是这样的:

[1, 100, 20]
[2, 120, 30]
[3, 150, -15]
[4, 135, 4]
…

这样做最有效的方法是什么?

4 个答案:

答案 0 :(得分:2)

我不太确定这个tbh的性能,所以你应该测试一下,但这是一种方式。我确定还有其他方法,所以这是一种可能性。正如我所说,表现将是我的主要关注点。

DECLARE @Data TABLE (ID INTEGER PRIMARY KEY, Total INTEGER, Diff INTEGER)
INSERT @Data VALUES (1, 100, 20)
INSERT @Data VALUES (2, NULL, 30)
INSERT @Data VALUES (3, NULL, -15)
INSERT @Data VALUES (4, NULL, 4)

DECLARE @StartingTotal INTEGER
SELECT @StartingTotal = Total FROM @Data WHERE ID = 1

UPDATE d
SET d.Total = @StartingTotal + TotalDiff
FROM @Data d
    CROSS APPLY (SELECT SUM(Diff) TotalDiff FROM @Data d2 WHERE d2.ID < d.ID) x
WHERE d.Total IS NULL

SELECT * FROM @Data

答案 1 :(得分:2)

好的,这是另一种选择。作为一个单独的答案添加,因为它是一个完全不同的方法。

这个假设是ID中没有间隙 - 这可能不太现实,但它证明了这种方法。如果ID中存在间隙,那么只需要对JOIN进行一些调整即可。

DECLARE @Data TABLE (ID INTEGER PRIMARY KEY, Total INTEGER, Diff INTEGER)
INSERT @Data VALUES (1, 100, 20)
INSERT @Data VALUES (2, NULL, 30)
INSERT @Data VALUES (3, NULL, -15)
INSERT @Data VALUES (4, NULL, 4)

DECLARE @PreviousTotal INTEGER
SELECT @PreviousTotal = Total
FROM @Data 
WHERE ID = 1

UPDATE d
SET @PreviousTotal = d.Total = @PreviousTotal + d2.Diff
FROM @Data d
    JOIN @Data d2 ON d.ID = d2.Id + 1

SELECT * FROM @Data 

答案 2 :(得分:0)

假设样本结果错误,并且它应该像评论中的marc_s一样,你可以这样做:

  • 第一条记录:

    INSERT into X Values(1, 100, 20)
    
  • 然后针对所有其他人(在第一列和最后一列中包含相应的iddiff值):

    INSERT into X SELECT TOP 1 2, total+diff, 30 FROM X ORDER BY id desc
    

不太好,但它确实有效。

答案 3 :(得分:0)

我通常不建议使用游标,但在这种情况下,它可能是一个不错的选择。 如果您担心性能,您需要测试这里给出的答案,以找出最适合您的方法。最佳解决方案可能因表中的行数而异。

declare @T as table (id int, total int, diff int)

insert into @T values (1, 100, 20)
insert into @T values (2, null, 30)
insert into @T values (3, null, -15)
insert into @T values (4, null, 4)

declare @id int
declare @diff int
declare @total int

select @total = total
from @T
where id = 1

declare cT cursor for select id, diff from @T order by id

open cT
fetch next from cT into @id, @diff
while (@@FETCH_STATUS <> -1)
begin
    update @T
    set total = @total
    where id = @id

    set @total = @total + @diff

    fetch next from cT into @id, @diff
end
close cT
deallocate cT

select *
from @T