SQL Server UPDATE和设置变量的同时,操作顺序

时间:2016-12-16 16:39:45

标签: sql-server

为什么在这段代码中@changed是正确的,但@ changed2不正确?目的是确定列值是否在update语句中发生更改。我没有找到任何可以解释这个细节的事情。

如果我不得不猜测,SQL Server将首先使用要更新的行的当前状态来设置变量,当它完成时它将实际更新它。这就是为什么@ changed2为0,在解析@ changed2变量时,VALUE列尚未更新,因此我们必须使用@newValue。

IF Object_id('tempdb..#tmpTest') IS NOT NULL 
  DROP TABLE #tmptest; 

CREATE TABLE #tmptest 
  ( 
     test_id INT NOT NULL IDENTITY(1, 1), 
     value   VARCHAR(20) 
  ); 

INSERT INTO #tmptest 
            (value) 
VALUES     ('hello'); 

然后多次运行此代码(您可以多次运行它,但不要再执行上面的代码!):

--then run this multiple times:
DECLARE @oldValue VARCHAR(20),
        @newValue VARCHAR(20) = (SELECT value
           FROM   #tmptest
           WHERE  test_id = 1),
        @changed  BIT,
        @changed2 BIT


--alternate values:
IF( @newValue = 'hello' )
  SET @newValue = 'goodbye'
ELSE
  SET @newValue = 'hello'

--see current data
SELECT *
FROM   #tmptest;

--update
UPDATE #tmptest
SET    value = @newValue,
       @oldValue = value,
       @changed = CASE
                    WHEN @oldValue != @newValue THEN 1
                    ELSE 0
                  END,
       @changed2 = CASE
                     WHEN @oldValue != value THEN 1
                     ELSE 0
                   END
WHERE  test_id = 1;

--see changed data:
SELECT *
FROM   #tmptest;

SELECT @oldValue oldValue,
       @newValue newValue,
       @changed  changed,
       @changed2 changed2

感谢您的时间。

1 个答案:

答案 0 :(得分:1)

执行更新时,如果需要知道原始记录上的值,SQL Server将在任何更新到位之前读取原始数据。因此,在您的示例中,过程将是这样的:

Read value as @OldValue
Compare @oldValue and value
    Set @changed
    Set @changed2
Update value from @newValue

在某些代码中涉及读取,更新和返回更新前值的某些代码实际上会依赖此行为,从而阻止其他进程检索相同的值。