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

Find modified fields in Update Trigger

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

我能想到的最紧凑的方法是执行以下类型的操作:

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

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

(这不需要为批量更新工作,不需要在 INSERTEDDELETED 中期望超过 1 条记录)

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

遗憾的是,我不知道有任何可靠的内置函数可以在更新语句触发触发器时指示列的值是否实际更改。

但是,您可以执行一个非常简单的 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 函数将 return null。如果不是,它 return 是第一列的值。

ISNULL 函数将 return 不是 null 的第一个参数,或者如果两个参数都为空则 null

如果两列的值相同,则对两个 NULLIF 函数的结果使用 ISNULL,其中列值被反转将导致 null,即使它们都为空。如果值不同,即使其中一个为空而另一个不为空,那么 ISNULL 将 return 一个值。因此,您所要做的就是检查 ISNULL return 是否为值或 null - 如果它 return null,您就知道该列的值未更改。如果它 return 是一个值,则它会被更改。

当然,对于不可为 null 的列,您可以像这样简化条件:

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

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

You can see a live demo on rextester.

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

IIF((I.Col IS NULL AND D.Col IS NULL) OR (I.Col = D.Col), 0, 1) as IsUpdated.

此方法依赖于将 null 与其他任何内容进行比较将得到 unknown 的事实,这基本上等同于 false.

恕我直言,它的可读性稍微好一些。