4

更新:使用 Update_Columns() 不是这个问题的答案,因为字段可能会按顺序更改,这会破坏触发器(Update_Columns 取决于列顺序)。

UPATE 2:我已经知道 Deleted 和 Inserted 表保存数据。问题是如何确定发生了哪些变化,而不必对字段名称进行硬编码,因为字段名称可能会更改,或者可能会添加字段。

假设我有一个包含三个字段的表。

该行已经存在,现在用户更新字段 1 和 2。

如何在更新触发器中确定更新了哪些字段,以及之前和之后的值在哪里?

然后我想将这些记录到日志表中。如果有两个字段更新,它应该在历史表中产生两行。

Table
Id  intField1  charField2  dateField3
7           3  Fred        1995-03-05

Updated To

7           3  Freddy      1995-05-06

History Table
_____________

Id  IdOfRowThatWasUpdated    BeforeValue    AfterValue (as string)
1                       7    Fred           Freddy
2                       7    1995-03-05     1995-05-06

我知道我可以使用 Deleted 表来获取旧值,并使用插入表来获取新值。然而,问题是如何动态地做到这一点。换句话说,实际的表有 50 列,我不想将 50 个字段硬编码到 SQL 语句中,如果字段发生变化,也不想担心保持 SQL 同步表的变化。

格雷格

4

2 回答 2

6

你可以使用我最喜欢的 XML 技巧之一来做到这一点:

create trigger utr_Table1_update on Table1
after update, insert, delete
as
begin
    with cte_inserted as (
        select id, (select t.* for xml raw('row'), type) as data
        from inserted as t
    ), cte_deleted as (
        select id, (select t.* for xml raw('row'), type) as data
        from deleted as t
    ), cte_i as (
        select
            c.ID,
            t.c.value('local-name(.)', 'nvarchar(128)') as Name,
            t.c.value('.', 'nvarchar(max)') as Value
        from cte_inserted as c
            outer apply c.Data.nodes('row/@*') as t(c)
    ), cte_d as (
        select
            c.ID,
            t.c.value('local-name(.)', 'nvarchar(128)') as Name,
            t.c.value('.', 'nvarchar(max)') as Value
        from cte_deleted as c
            outer apply c.Data.nodes('row/@*') as t(c)
    )
    insert into Table1_History (ID, Name, OldValue, NewValue)
    select
        isnull(i.ID, d.ID) as ID,
        isnull(i.Name, d.Name) as Name,
        d.Value,
        i.Value
    from cte_i as i
        full outer join cte_d as d on d.ID = i.ID and d.Name = i.Name
    where
        not exists (select i.value intersect select d.value)

结尾;

sql fiddle demo

于 2013-09-29T11:39:16.170 回答
0

在这篇文章中:

如何在 SQL Server 中引用触发器的“新”、“旧”行?

提到/如何访问原始值和新值,如果可以访问,则可以比较它们。

“INSERTED 是 INSERT/UPDATE 上的新行。DELETED 是 DELETE 上的已删除行和 UPDATE 上的更新行(即更新行之前的旧值)”

于 2013-09-29T11:12:30.460 回答