如何确定更新触发器中更新的字段

时间:2013-09-29 11:08:37

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

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

更新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表来获取旧值,并使用inserted表来获取新值。然而,问题是如何动态地这样做。换句话说,实际的表有50列,我不想将50个字段硬编码到SQL语句中,如果字段发生变化,也不想担心保持SQL同步表格变化。

格雷格

2 个答案:

答案 0 :(得分:6)

您可以使用我的favorite XML-tricks之一执行此操作:

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

答案 1 :(得分:0)

在这篇文章中:

How to refer to "New", "Old" row for Triggers in SQL server?

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

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