T-SQL:更新后COLUMNS发生了哪些变化?

时间:2010-01-26 00:45:29

标签: sql-server sql-server-2005 tsql

行。我正在对表中的单行进行更新。 除主键外,所有字段都将被新数据覆盖。 但是,并非所有值都会更改更新的b / c。 例如,如果我的表格如下:

TABLE (id int ident, foo varchar(50), bar varchar(50))

初始值为:

id   foo   bar
-----------------
1    hi    there

然后我执行UPDATE tbl SET foo = 'hi', bar = 'something else' WHERE id = 1

我想知道的是哪个列的值已更改,其原始值是什么以及它的新值是什么。

在上面的示例中,我希望看到“bar”列已从“there”更改为“其他内容”。

可以不进行逐列比较吗?是否有一些优雅的SQL语句,如EXCEPT,它将比行更精细?

感谢。

6 个答案:

答案 0 :(得分:9)

没有可以运行的特殊声明会告诉您确切的列已更改,但是查询并不难写:

DECLARE @Updates TABLE
(
    OldFoo varchar(50),
    NewFoo varchar(50),
    OldBar varchar(50),
    NewBar varchar(50)
)

UPDATE FooBars
SET <some_columns> = <some_values>
OUTPUT deleted.foo, inserted.foo, deleted.bar, inserted.bar INTO @Updates
WHERE <some_conditions>

SELECT *
FROM @Updates
WHERE OldFoo != NewFoo
OR OldBar != NewBar

如果您因为这些更改而尝试做某事,那么最好写一个触发器:

CREATE TRIGGER tr_FooBars_Update
ON FooBars
FOR UPDATE AS
BEGIN
    IF UPDATE(foo) OR UPDATE(bar)
        INSERT FooBarChanges (OldFoo, NewFoo, OldBar, NewBar)
            SELECT d.foo, i.foo, d.bar, i.bar
            FROM inserted i
            INNER JOIN deleted d
                ON i.id = d.id
            WHERE d.foo <> i.foo
            OR d.bar <> i.bar
END

(当然你可能想要在触发器中做更多的事情,但是有一个非常简单的动作的例子)

您可以使用COLUMNS_UPDATED代替UPDATE,但我觉得它很痛苦,而且它仍然不会告诉您哪些列实际更改了,哪些列是包含在UPDATE声明中。例如,您可以编写UPDATE MyTable SET Col1 = Col1,它仍然会告诉您Col1已更新,即使实际上没有一个值发生更改。在编写触发器时,您需要实际测试单个前后值,以确保您获得真正的更改(如果这是您想要的)。

P.S。你也可以像Rob说的那样UNPIVOT,但你仍然需要在UNPIVOT子句中明确指定列,这不是魔术。

答案 1 :(得分:2)

尝试对已插入和已删除的内容进行解除隐藏,然后您可以加入,查找值已更改的位置。

答案 2 :(得分:1)

您可以在触发器中检测到这一点,或在SQL Server 2008中使用CDC

如果您create a trigger FOR AFTER UPDATE,则inserted表将包含具有新值的行,deleted表将包含具有旧值的相应行。

答案 3 :(得分:0)

OUTPUT deleted.bar AS [OLD VALUE], inserted.bar AS [NEW VALUE]

@Calvin我只是基于UPDATE示例。我并不是说这是完整的解决方案。我提示你可以在代码中的某个地方执行此操作; - )

由于我已经从上面的答案得到-1,让我把它放在:

如果您真的不知道哪个列已更新,我会说创建一个触发器并在该触发器的主体中使用COLUMNS_UPDATED()函数(参见this

我在我的博客中创建了一个Bitmask Reference,用于此COLUMNS_UPDATED()。如果您决定遵循此路径,它将使您的生活更轻松(Trigger + Columns_Updated())

如果你不熟悉触发器,这是我的基本触发器示例http://dbalink.wordpress.com/2008/06/20/how-to-sql-server-trigger-101/

答案 4 :(得分:0)

如果您使用的是SQL Server 2008,则应该查看新的“更改数据捕获”功能。这将做你想要的。

答案 5 :(得分:0)

跟踪数据更改的备选选项是将数据写入另一个(可能的临时)表,然后使用XML分析差异。更改的数据与列名一起写入审计表。只有一件事是你需要知道表字段来准备临时表。 你可以在这里找到这个解决方案: