SQL Server:在CROSS APPLY期间从函数中提取更新的数据

时间:2017-04-21 17:48:34

标签: sql-server sql-server-2014 cross-apply

快速摘要:我有一个从表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.sampleDataCROSS APPLY的更新值在UPDATE

期间

欢迎任何想法。

2 个答案:

答案 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=100 BO.sampleData where id = 11(来自id = 10 from @info),然后交叉申请,它处理{val = 10 1}},即val

一切都在您的UDF中。当您的UDF中@info的id = 10时,没有更新@info到27,请注意t0,t1,t2表格已返回