【问题标题】:Find modified fields in Update Trigger在更新触发器中查找修改的字段
【发布时间】:2019-07-06 06:40:48
【问题描述】:

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 条记录”,直到你明白这一点......最好不要假设这样的假设。
  • 当您发现哪些列已更新时,您的实际目标是什么?如果它只是记录旧值,那么通常您只需完整记录整行是否有 1 或 100 列已更新。否则,可能是SQL update trigger only when column is modified的重复?
  • 如果您不希望获得多行并且不打算正确处理多行,那么您的触发器应该通过在遇到多行时抛出错误来强制执行此假设。为什么?因为它总有一天会发生。
  • 如果你想要一种带有 CURSOR 的方法,为什么不写一个?
  • @TabAlleman 我在问是否有任何方法可以使用光标选择所有修改过的字段并为每个字段执行特定操作

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


【解决方案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

在两个列值颠倒的NULLIF 函数的结果上使用ISNULL 将导致null 如果两列的值相同,即使它们都为空。如果值不同,即使其中一个为空而另一个不为空,ISNULL 也会返回一个值。因此,您所要做的就是检查ISNULL 是否返回了一个值或null - 如果它返回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

恕我直言,它的可读性略高。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多