TSql Trigger只需要在值已更改的列上触发

时间:2010-01-05 17:44:37

标签: sql-server tsql triggers

我编写了一个触发器,需要根据实际更新的行中的哪些列对表执行一些不同的工作。我用

完成了这个
IF UPDATE(column-name)

那部分工作正常。然而,事实证明,代码的其他部分通过设置每个值来更新行,无论值是否实际更改,这会导致触发器触发“已更新”但其值实际上未更改的部分一点都不

由于更改导致此问题的代码可能不是一个选项,除了必须在INSERTED和DELETED表之间进行比较之外,还有一种更简单的方法可以防止这种情况(在这种情况下,IF UPDATE是没有意义的)吗?

4 个答案:

答案 0 :(得分:14)

IF EXISTS (SELECT *
          FROM
             INSERTED I JOIN DELETED D ON I.Key = D.Key
          WHERE
             I.Col <> D.Col)
...

或使用表变量进行缓存,以避免重复使用I和D.

SELECT
    CASE WHEN I.Col1 <> D.Col1 THEN 1 ELSE 0 END AS Col1Diff,
    CASE WHEN I.Col2 <> D.Col2 THEN 1 ELSE 0 END AS Col2Diff,
    ...
FROM
    INSERTED I JOIN DELETED D ON I.Key = D.Key

或组合想法以预先测试所有更改并退出触发器

答案 1 :(得分:7)

正如其他人所说,你必须使用INSERTEDDELETED表。

这是我所做的,而不是:

IF UPDATE(col1) OR UPDATE(col2))
UPDATE table1
SET col3 = 1
FROM INSERTED
WHERE table1.Id = INSERTED.Id

我做了:

IF UPDATE(col1) OR UPDATE(col2))
 UPDATE table1
 SET col3 = 1
 FROM 
  (SELECT Id, col1, col2 FROM INSERTED 
   EXCEPT 
  SELECT Id, col1, col2 FROM DELETED) AS ALTERED
 WHERE table1.Id = ALTERED.Id

使用EXCEPT选择我感兴趣的列不存在于删除(或原始数据)表中的不同行(意味着这些列的值已更改)。我不知道这是否是最好的答案,但似乎确实有效。

答案 2 :(得分:4)

该列已更新。旧值和新值相同只是一个细节。我认为你唯一的解决方案是比较插入和删除的伪表之间的值。

答案 3 :(得分:2)

不是我知道的。 INSERTEDDELETED是有原因的,相比它们似乎是我的最佳选择。

IF UPDATE()只是告诉您是否插入或更新尝试,甚至不反映该尝试是否成功。