USE [MY_DATABASE_NAME]
GO
/****** Object: Trigger [dbo].[trg_After_Update] Script Date: 16.12.2014 23:13:53 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[trg_After_Update]
ON [dbo].[MY_TABLE_NAME]
FOR UPDATE
AS
declare @FOR_DATE date;
declare @WRITTEN_ON smalldatetime;
declare @WRITTEN_BY_WHO NVARCHAR(50);
declare @REPORT nvarchar(max);
declare @HANDLED bit;
declare @HANDLED_BY NVARCHAR(50);
declare @HANDLED_WHEN datetime;
declare @COMMENT nvarchar(max);
declare @AUDIT_ACTION NVARCHAR(50);
declare @AUDIT_TIMESTAMP smalldatetime;
select @FOR_DATE = i.FOR_DATE from inserted i;
select @WRITTEN_ON = i.WRITTEN_ON from inserted i;
select @WRITTEN_BY_WHO = i.WRITTEN_BY_WHO from inserted i;
select @REPORT = i.REPORT from inserted i;
select @HANDLED = i.HANDLED from inserted i;
select @HANDLED_BY = i.HANDLED_BY from inserted i;
select @HANDLED_WHEN = i.HANDLED_WHEN from inserted i;
select @ COMMENT = i.COMMENT from inserted i;
if update(REPORT)
set @audit_action='Report change';
if update(COMMENT)
set @audit_action='Comment change';
if update(HANDLED)
set @audit_action='Handled change';
insert into AUDIT_MY_TABLE_NAME
(FOR_DATE,WRITTEN_ON,WRITTEN_BY_WHO,REPORT,HANDLED,HANDLED_BY,HANDLED_WHEN,COMMENT,USER,AUDIT_ACTION,AUDIT_TIMESTAMP)
values
(@FOR_DATE,@WRITTEN_ON,@WRITTEN_BY_WHO,@REPORT,@HANDLED,@HANDLED_BY,@HANDLED_WHEN,@COMMENT,USER_NAME(USER_ID()),@audit_action,getdate());
此触发器或多或少地按预期工作。它记录3个受监视字段的任何更改。但是,在此表'MY_TABLE_NAME'中插入新记录会触发上述触发器。然后,当我去看审计表'AUDIT_MY_TABLE_NAME'时,我看到这个新记录已添加到那里。唯一的区别是'audit_action'字段为空。 此插入审核表可能是由于另一个触发器更新了'MY_TABLE_NAME'after_insert中的2个字段。
我的问题是:我有点像这个触发器的工作方式。我想添加的唯一附加功能是'audit_action'读取'New record'而不是现在显示为空。请注意,我没有记录新记录但是因为After_Update触发器仍然记录它们,为什么不... 那么我必须在这个'after_update'触发器中更改什么,以便在插入新记录时,我的审计表中有'audit_action'读取'New record'?
答案 0 :(得分:2)
在为单个更新编写触发器时要非常小心,但不要阻止批量更新的日志记录。如果您批量更新20条记录,您将在审计表中获得1个插入,这将是20个中随机的一个。
为了满足您的条件而不会有太大变化,您可以像这样修改触发器(这会处理批量更新):
ALTER TRIGGER [dbo].[trg_After_Update]
ON [dbo].[MY_TABLE_NAME]
FOR UPDATE
AS
INSERT INTO AUDIT_MY_TABLE_NAME (FOR_DATE,WRITTEN_ON,WRITTEN_BY_WHO,REPORT,HANDLED,HANDLED_BY,HANDLED_WHEN,COMMENT,USER,AUDIT_ACTION,AUDIT_TIMESTAMP)
SELECT i.FOR_DATE, i.WRITTEN_ON, i.WRITTEN_BY_WHO, i.REPORT, i.HANDLED, i.HANDLED_BY, i.HANDLED_WHEN, i.COMMENT, USER_NAME(USER_ID()),
CASE -- case statement is in reverse order to match your logic (bottom wins)
WHEN i.HANDLED <> d.HANDLED THEN 'Handled Changed'
WHEN i.COMMENT <> d.COMMENT THEN 'Comment Change'
WHEN i.REPORT <> d.REPORT THEN 'Report Change'
ELSE 'New Record'
END,
GETDATE()
FROM inserted i
LEFT JOIN deleted d ON i.pk = d.pk -- join on your Primary Key that doesn't change
END
但我想知道你认为发生的事情是否正确。当您更新这3个字段中的1个以上时,所有逻辑都将运行。如果您的3中有超过1列正在更新,则最后一列会获胜。我的猜测是,您的“新记录”更新实际上是正在更新的3 UPDATE
列之外的字段。
这是另一种选择,我会让你选择你认为最好的选择:
ALTER TRIGGER [dbo].[trg_After_Update]
ON [dbo].[MY_TABLE_NAME]
FOR UPDATE
AS
INSERT INTO AUDIT_MY_TABLE_NAME (FOR_DATE,WRITTEN_ON,WRITTEN_BY_WHO,REPORT,HANDLED,HANDLED_BY,HANDLED_WHEN,COMMENT,USER,AUDIT_ACTION,AUDIT_TIMESTAMP)
SELECT i.FOR_DATE, i.WRITTEN_ON, i.WRITTEN_BY_WHO, i.REPORT, i.HANDLED, i.HANDLED_BY, i.HANDLED_WHEN, i.COMMENT, USER_NAME(USER_ID()),
CASE WHEN i.pk IS NOT NULL AND d.pk IS NULL THEN 'New Record' ELSE
CASE WHEN i.HANDLED <> d.HANDLED THEN 'Handled Changed. ' ELSE '' END +
CASE WHEN i.COMMENT <> d.COMMENT THEN 'Comment Change. ' ELSE '' END +
CASE WHEN i.REPORT <> d.REPORT THEN 'Report Change. ' ELSE '' END +
CASE WHEN i.HANDLED = d.HANDLED AND i.COMMENT = d.COMMENT AND i.REPORT = d.REPORT THEN 'Other Change.' ELSE '' END
END,
GETDATE()
FROM inserted i
LEFT JOIN deleted d ON i.pk = d.pk -- join on your Primary Key that doesn't change
END