SQL Server 2016 UPDATE 语句 - 变量赋值是否始终在列更新之前处理?

Fru*_*aun 2 sql-server t-sql

我们的一位应用程序开发人员向我提出了一个有趣的问题。在下面的代码中,您将看到更新语句将当前列值分配给两个变量,同时还将这些相同的列更新为新值。

\n

问题是,是否保证变量@oStart和@oFinish将被分配给[Start]和[Finish]的值而不是值?在测试中,情况确实如此,但是,我想确认这是有保证的行为。

\n

我预计答案是“不 - 不能保证”,最终,这取决于优化器所做的决定。无论如何,无论如何,这种模棱两可的代码都是不鼓励的(有更优雅和可读的编写方式),但有兴趣听到每个人的想法。

\n
-- Parameters\nDECLARE @StartDate smalldatetime = '2022-01-01',\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 @EndDate smalldatetime = '2022-12-31';\n\n-- Body\nDECLARE @oStart smalldatetime,\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 @oFinish smalldatetime;\n\nUPDATE\xc2\xa0 [dbo].[MyTable]\nSET\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 @oStart = [Start],\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 @oFinish = [Finish],\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 [Start] = @StartDate,\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 [Finish] = @EndDate\nWHERE\xc2\xa0\xc2\xa0 [ID] = 12;\n
Run Code Online (Sandbox Code Playgroud)\n

Mar*_*ith 8

是的,这是有记录的。@variable请参阅语法中的文档UPDATE

SET @variable = column...将变量设置为列的更新前值。

(与文档中的对比,SET @variable = column = expression它将变量设置为赋值后的column = expression值)。

DECLARE @oldStart  SMALLDATETIME,
        @oldFinish SMALLDATETIME,
        @newStart  SMALLDATETIME,
        @newFinish SMALLDATETIME;

DECLARE @MyTable TABLE
  (
     ID     INT PRIMARY KEY,
     Start  SMALLDATETIME,
     Finish SMALLDATETIME
  )

INSERT @MyTable
VALUES(12, '1900-01-01', '1900-01-31');

UPDATE @MyTable
SET    @oldStart = [Start],
       @oldFinish = [Finish],
       @newStart = [Start] = '2022-01-01',
       @newFinish = [Finish] = '2022-12-31'
WHERE  [ID] = 12;

SELECT @oldStart  AS [@oldStart],
       @oldFinish AS [@oldFinish],
       @newStart  AS [@newStart],
       @newFinish AS [@newFinish]; 
Run Code Online (Sandbox Code Playgroud)

退货

@oldStart @旧完成 @新的开始 @newFinish
1900-01-01 00:00:00 1900-01-31 00:00:00 2022-01-01 00:00:00 2022-12-31 00:00:00

假设ID是主键,因此UPDATE保证最多影响一行,那么我个人认为,如果您需要将该值分配给 SQL 变量,那么这种语法就很好。

它优于必须使用子句OUTPUT ... INTO将这些值存储在某处,然后将SELECT其后续值分配给变量。


mus*_*cio 5

SQL标准规定

在更新 T 的任何行之前,将针对 [table] T 的每一行有效评估 SCL [Set Clause List] 中包含的每个 <set Clause> 的 <update source>

(强调我的)。在您的情况下,这意味着根据标准,@oStart和必须分别具有和@oFinish的值,因为它们在更新之前就存在。[Start][Finish]

现在,SQL Server 在这方面是否符合标准是一个不同的问题。