更新:使用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同步表格变化。
格雷格
答案 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上更新的行(即行更新前的旧值)”