在update语句中分配给局部变量

时间:2015-02-21 13:45:19

标签: sql sql-server tsql

下一个代码和平意味着什么:

update dbo.dbr_schem
set @expr=isnull(@expr+' union all ','') 
+'select ' 
+ cast(pozycja as varchar)  + ','
+ cast(schemat as varchar)  + ',' 
+ cast(nardolny as varchar) + ',' 
+ cast(nargorny as varchar) + '' +
          case when warunekSQL<>'' then ' where ' + warunekSQL else '' end
where indeks=@indeks

看起来像是简单地分配给局部变量,但为什么它在update语句中使用?

1 个答案:

答案 0 :(得分:1)

在UPDATE中更新局部变量称为&#34; quirky update&#34;。当需要在诸如运行总计之类的场景中跨越更新行传递值时,通常使用它。这在SQL Server 2012中引入窗口函数之前的一个特性中更为重要。这里有一个相当不错的讨论,其中包含了有助于阅读的各种其他文章和论坛的链接:

Please can somebody explain how quirky updates work?

在这种特殊情况下,它似乎没有比在SELECT中这样做有任何好处。这是因为在设置变量的同时不会更新表的字段。能够处理除变量之外的真实字段是可以在SELECT语句中完成的事情(即你不能做SELECT field1, @variable = @variable + field2 FROM Table),这就是为什么古怪的更新是有时候非常方便。因此,这种特殊用法可以变成一个没有功能差异的SELECT,因为它只是创建一个动态SQL字符串。

UPDATESELECT之间此特定用法中唯一可能的功能差异可能可能是连接到的值的顺序串。原因是群集索引按照群集索引排序,而将其更改为SELECT,而无需添加ORDER BY的其他更改,则没有保证顺序。

就日志记录而言,由于此UPDATE语句中没有更新任何内容,因此不会将任何内容写入事务日志。我已通过测试仅变量方案(即当前问题)以及UPDATE确认了这一点,该SET确实在WHERE子句中指定了字段但没有与SNAPSHOT匹配的行条款。在任何情况下都没有记录任何内容,即使显式事务已启动并已提交。

请注意,就锁定而言,如果您使用的是UPDATE事务隔离级别,那么在使用{{1}时将会采用更少(且影响更小)的锁定因此它与使用SELECT之间应该没有什么区别(因为这里实际上没有更新任何行)。否则,UPDATESELECT似乎都采用相同数量的锁。不过,区别在于UPDATE需要&#34;独家&#34;锁定,而SELECT只需要#34;共享&#34;锁。自&#34;共享&#34;锁定对其他进程的影响较小,并且允许更多的并发性,因为此表中没有实际的字段正在更新,此查询确实应该转换为SELECT

SELECT @expr = ISNULL(@expr + ' union all ', '') 
+'select ' 
+ cast(pozycja AS VARCHAR(50))  + ','
+ cast(schemat AS VARCHAR(50))  + ',' 
+ cast(nardolny AS VARCHAR(50)) + ',' 
+ cast(nargorny AS VARCHAR(50)) + '' +
          CASE WHEN warunekSQL<>'' THEN ' where ' + warunekSQL
               ELSE ''
          END
FROM dbo.dbr_schem
WHERE indeks = @indeks;

请注意,在上面的查询中,我指定了CAST AS VARCHAR的长度/大小,否则在问题的查询中未指定。可变长度数据类型不应保留为未指定,因为默认值为1或30,具体取决于执行该操作的情况。