[英]Writing an iterative self-referential SQL query
我有一個復雜的算法需要在 SQL 中實現,其中算法需要能夠為第一行計算某個值,並且在所有后續行上都需要能夠使用前一行的計算值作為其自身的一部分計算。 它是遞歸的,但從包含所有 NULL 的目標列的 position 開始。
我在下面使用 cursor 簡化了解決此問題的嘗試:
if object_id('tempdb..#t') is not null
drop table #t;
-- create a simple demo table containing IDs 1 - 10 and an empty int column
with cte as (
select x = 1
union all
select x = x + 1
from cte
where x < 10
)
select *, WriteVal = cast(null as int)
into #t
from cte
declare c cursor for
select x from #t
declare @x int
open c
fetch next from c into @x
while @@FETCH_STATUS = 0
begin
declare @WriteVal int
-- Set @WriteVal to the previous row's [WriteVal] + 10. If previous row's [WriteVal] is NULL,
-- (i.e. we're in the first row), use 0 + 10 instead.
select @WriteVal = isnull(lag(WriteVal, 1) over (order by x), 0) + 10
from #t
where x = @x
-- Update this row on the temp table with the value stored in @WriteVal
update #t
set WriteVal = @WriteVal
where x = @x
-- return the full table for debugging
select *, [@WriteVal] = @WriteVal
from #t
fetch next from c into @x
end
close c
deallocate c
起始數據集:
x | WriteVal
----|---------
1 | NULL
2 | NULL
3 | NULL
4 | NULL
...
10 | NULL
我期待看到的是:
lag(WriteVal, 1)
是 NULL,所以@WriteVal
設置為 10,然后將10
寫入第 1 行的[WriteVal]
lag(WriteVal, 1)
為 10,因此@WriteVal
設置為 (10 + 10) 20,然后將20
寫入第 2 行的[WriteVal]
lag(WriteVal, 1)
為 20,因此@WriteVal
設置為 (20 + 10) 30,然后將30
寫入第 3 行的[WriteVal]
預期結果集:
x | WriteVal
----|---------
1 | 10
2 | 20
3 | 30
4 | 40
...
10 | 100
實際返回的是每個[WriteVal]
設置為10
,進一步檢查將表明后續循環迭代無法識別更新的前一行的值,因此lag(WriteVal, 1)
總是返回 NULL。 我認為某些優化或緩存機制應歸咎於此,或者直到查詢完成或其他事情才真正提交更新。
實際結果集:
x | WriteVal
----|---------
1 | 10
2 | 10
3 | 10
4 | 10
...
10 | 10
我該如何解決這個問題? 有更好的方法嗎? 如果可能的話,我寧願避免使用游標,但事實上它需要能夠首先計算第n行,然后將結果用於第n + 1行,這意味着我對使用 self 的非游標解決方案沒有任何運氣-joins 或 window 函數
根據您的樣本數據,您需要:
select x,
10 * row_number() over (order by x) as writeval
from #t;
要更新這些值,請使用可更新的 CTE:
with toupdate as (
select t.*,
10 * row_number() over (order by x) as new_writeval
from #t t
)
update toupdate
set writeval = new_writeval;
請注意,您的查詢返回的結果不一致,因為您的 cursor 不使用order by
,因此結果可能會在調用之間發生變化。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.