代码之家  ›  专栏  ›  技术社区  ›  noober

我想知道,哪些栏目真正改变了

  •  4
  • noober  · 技术社区  · 15 年前

    我在sqlcr程序集中实现了after触发器。在其中,我想知道哪些列已经真正更新了(它们的值已经更改)。

    不幸的是,即使列值仍然相同,sqlcontext.triggerContext.isUpdatedColumn也返回true。我想,这仅仅是因为一个由不太智能的服务器应用程序准备的SQL查询重写了所有列,即使其中一些列没有被用户更改。

    第二个问题是有些列具有ntext类型,因此我甚至无法从插入的伪表中选择它们(MS SQL Server不允许选择具有ntext类型的字段)。这就是为什么现在我用以下查询选择已更改的行:

    SELECT * FROM [dbo].[MyTable] WHERE [id] IN (SELECT [id] FROM INSERTED)
    

    我该怎么做才能知道,哪些列不仅被更新,而且被更改了?

    现在我有了一个简单的想法:在前面创建另一个触发器,并从内部保存更新的行。然后,在执行触发器之后,比较列值。这是我能做的最好的事吗?如果是,在触发器之前和之后保存更改行的最佳位置是什么?在执行after触发器之前将删除一个临时表,因为我关闭了上下文连接(可能,只是不关闭?).

    1 回复  |  直到 15 年前
        1
  •  2
  •   noober    15 年前

    好吧,现在我已经解决了这个问题。

    首先,我创建了源表(数据+结构)的完整副本:

    IF NOT EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'copyTable')
    SELECT * INTO copyTable FROM MyTable
    

    然后,我将源表与其触发器开始时的副本进行比较:

    SELECT A.* FROM MyTable A, copyTable B WHERE
        A.id IN (SELECT [id] FROM INSERTED) AND
        A.id = B.id AND
        A.{0} <> B.{0}
    

    将0替换为所需的列。此列正是您必须知道的列,是否已更新。在我的例子中,它是动态定义的,但是您可以静态地计算您需要的所有列。

    等等-你只选择了真正改变的行。

    最后,在触发器的末尾,不要忘记用新值更新copytable:

    UPDATE copyTable SET
        id = s.id,
        col1 = s.col1,
        ... all columns you'd like to control ...
    FROM MyTable s WHERE
        s.id IN (SELECT [id] FROM INSERTED) AND
        copyTable.id = s.id
    

    也许,有一个更好的解决方案,但这也是可行的。

    当做,