快速摘要:我有一个从表X
中提取数据的函数。我在表UPDATE
上运行X
,并在正在从CROSS APPLY
提取数据的函数上使用X
(在更新期间)并且函数没有& #39; t看起来要返回更新的数据。
真实世界的场景要复杂得多,但这里是我所看到的样本。
create table BO.sampleData (id int primary key, data1 int, val int)
create function BO.getPrevious(
@id int
)
returns @info table (
id int, val int
)
as
begin
declare @val int
declare @prevRow int = @id - 1
-- grab data from previous row
insert into @info
select @id, val
from BO.sampleData where id = @prevRow
-- if previous row doesn't exist, return 3*prev row id
if @@rowcount = 0
insert into @info values (@id, @prevRow * 3)
return
end
填充一些样本数据:
delete BO.sampleData
insert into BO.sampleData values (10, 20, 0)
insert into BO.sampleData values (11, 22, 0)
insert into BO.sampleData values (12, 24, 0)
insert into BO.sampleData values (13, 26, 0)
insert into BO.sampleData values (14, 28, 0)
select * from BO.sampleData
id data1 val
----------- ----------- -----------
10 20 0
11 22 0
12 24 0
13 26 0
14 28 0
使用BO.sampleData
上的CROSS APPLY
更新BO.getPrevious
(访问来自BO.sampleData
的数据):
update t
set t.val = ca.val
from bo.sampleData t
cross apply BO.getPrevious(t.id) ca
where t.id = ca.id
我希望id为10的行的值为27(因为没有第9行,函数将返回9 * 3)。对于id 11,我假设它会查看10(刚刚更新为27)并将其设置为27 - 这将使表的其余部分级联。但我得到的是:
id data1 val
----------- ----------- -----------
10 20 27
11 22 0
12 24 0
13 26 0
14 28 0
我猜这是不允许/支持的 - 该功能还无法访问更新的数据吗?或者我的语法有问题?在我研究的真实场景中,函数要复杂得多,在返回结果之前,有些子表会查找,聚合等等。但这代表了我所看到的基础知识 - 查询BO.sampleData
的功能似乎无法访问BO.sampleData
中CROSS APPLY
的更新值在UPDATE
。
欢迎任何想法。
答案 0 :(得分:2)
感谢@Martin Smith确定问题 - 即“万圣节保护”。既然我的问题有一个名字,我做了一些研究,发现following article在SQL Server中提到了这个特定的场景:
...更新计划由两部分组成:一个标识的读取光标 要更新的行和实际执行的写入游标 更新。从逻辑上讲,SQL Server必须执行读取游标 并在两个单独的步骤或阶段中写入更新计划的光标。 换句话说,行的实际更新不得影响 选择要更新的行。
强调我的。现在有道理。 CROSS APPLY
发生在读取光标上,其中所有值仍为零。
答案 1 :(得分:0)
数据始终来自@info
对于输入id = 11,它将执行:
insert into @info
select @id, val --which @id = 10, val = 0
from BO.sampleData where id = 10
所以@info
val
id=10
为0
BO.sampleData where id = 11
(来自id = 10 from @info
),然后交叉申请,它处理{val = 10
1}},即val
。
一切都在您的UDF中。当您的UDF中@info
的id = 10时,没有更新@info
到27,请注意t0,t1,t2
表格已返回。