在更新触发器中查找修改的字段

时间:2019-02-12 15:08:29

标签: sql sql-server tsql triggers sql-server-2008-r2

Update Trigger中获取所有已修改字段的列表的最简单方法是什么?

我能想到的最紧凑的方法是做某种类型的事情:

IF EXISTS(SELECT 1 FROM INSERTED INNER JOIN DELETED ON INSERTED.[FIELD_TO_CHECK] = DELETE.[FIELD_TO_CHECK])

但这将意味着我必须对要检查的每个字段执行此操作。我希望使用cursor包含有关所有已修改字段的信息的方法。

(不需要进行大量更新,INSERTEDDELETED中不需要多于1条记录)

我添加了一个if语句来忽略大量更新,因为它们属于不同的类别。

1 个答案:

答案 0 :(得分:1)

不幸的是,我不知道有任何可靠的内置函数可以为您提供指示,当更新语句触发触发器时,列的值是否实际发生了变化。

但是,您可以执行一个非常简单的select语句来查看哪些值在哪些行中发生了变化:

SELECT IIF(ISNULL(NULLIF(I.Col, D.Col), NULLIF(D.Col, I.Col)) IS NULL, 0, 1) As Col_Updated
FROM Inserted I
JOIN Deleted D
    ON I.PrimaryKey = D.PrimaryKey

如果两列相等,则NULLIF函数将返回null。如果不是,则返回第一列的值。

ISNULL函数将返回不是null的第一个参数,如果两个参数都为null,则返回null

在两个ISNULL函数的结果上使用NULLIF时,如果两个列的值相同,即使它们都为null,它们的列值也将相反。如果值不同,则即使其中一个为null而另一个不是,则null将返回一个值。因此,您要做的就是检查ISNULL是否返回值或为null-如果返回ISNULL,则表明该列的值未更改。如果返回值,则将其更改。

当然,对于不可为空的列,您可以简化如下条件:

null

但是我建议反对,因为如果有人将列更改为允许null,则触发代码将不得不更改以支持该操作-以我的经验,这是一个等待发生的错误-触发代码可能不会更改,从而导致假阴性。

You can see a live demo on rextester.

更新
您可以使用的另一种简单方法是:

SELECT IIF(I.Col <> D.Col, 1, 0) As Col_Updated
FROM...

此方法依赖于这样的事实:将null与其他任何内容进行比较都会得到IIF((I.Col IS NULL AND D.Col IS NULL) OR (I.Col = D.Col), 0, 1) as IsUpdated. ,该结果基本上等同于unknown

恕我直言,这更具可读性。