我正在尝试编写一个触发器来审核表的每个字段 - 一行中的旧值和表中的新值。如果任何字段已被修改,我需要将字段旧值和新值以及字段名称一起保存在审计表中,作为新条目。
create trigger Trg_Institution_FieldAudit on Table1 AFTER UPDATE AS
DECLARE @OldName VARCHAR(30)
DECLARE @CurrentName VARCHAR(30)
DECLARE @OldId VARCHAR(30)
DECLARE @CurrentId VARCHAR(30)
DECLARE @modifiedBy VARCHAR(30)
If update(Name)
BEGIN
select @OldName = Name from deleted
select @CurrentName = Name from Inserted
select @OldId = ID from deleted
select @currentId = ID from Inserted
select @modifiedBy = modifiedBy from deleted
--INSERT statement for Name field alone
END;
这适用于少数字段,但我有很多字段(超过60个),并且我没有达到所需的性能,因为有很多if条件。有没有更好的方法呢?除此之外,此表中有大约300万条记录发生并发更新,这会导致很多问题出现:(
编辑:UPDATE语句只会更新一行
答案 0 :(得分:2)
哦,我的。请尽量避免使用光标!您可以轻松地使用带有select引用insert和deleted表的insert语句。以下是我的一个更新触发器的示例。
DECLARE @AuditTime DATETIME
SET @AuditTime = GetDate()
IF UPDATE([AccountManager])
INSERT INTO Audit.AuditHistory (AuditId, AuditDate, AuditTableName, EntityKey, AuditFieldName, OldValue, NewValue, FieldDisplayText, OldDisplayText, NewDisplayText, ModifiedBy)
SELECT NewId(),
@AuditTime,
'[tblOpportunity]',
cast(d.[GOTSID] AS varchar),
'[AccountManager]',
cast(d.[AccountManager] AS varchar(250)),
cast(i.[AccountManager] AS varchar(250)),
'Account Manager',
isnull(cast(d.[AccountManager] AS varchar(250)), ''),
isnull(cast(i.[AccountManager] AS varchar(250)), ''),
isnull(i.[ModifiedBy], '')
FROM deleted d
INNER JOIN inserted i ON d.GOTSID = i.GOTSID
WHERE d.[AccountManager] <> i.[AccountManager]
OR (d.[AccountManager] IS NOT NULL
AND i.AccountManager IS NULL)
OR (d.[AccountManager] IS NULL
AND i.AccountManager IS NOT NULL)
答案 1 :(得分:0)
@marc_s是对的,你必须重新构建你的触发器和表。举个例子。
你需要在select中选择@OldName = Name的条件。
例如 -
**
CREATE TRIGGER Trg_Institution_FieldAudit ON Table1 FOR UPDATE
AS
DECLARE @OldName VARCHAR(30)
DECLARE @CurrentName VARCHAR(30)
IF UPDATE (Name)
BEGIN
SET @OldName = Table1.Name FROM deleted
WHERE Table1.Name = deleted.Name;
SET @CurrentName = Table1.Name FROM inserted
WHERE Table1.Name = inserted.Name ;
--INSERT statement for old and new values.
END
GO**
答案 2 :(得分:0)
在SQL Server中寻找FOR EACH的替代方案后,我发现可以使用CURSOR。它有用,但需要有人来验证这一点。
CREATE TRIGGER Trg_Institution_FieldAudit_1 ON dbo.Institution FOR UPDATE as
-- DECLARE Variables
DECLARE institution_cursor CURSOR DYNAMIC FOR SELECT * FROM DELETED
OPEN institution_cursor FETCH NEXT FROM institution_cursor INTO -- @variables here
WHILE (@@FETCH_STATUS = 0)
BEGIN
IF UPDATE(COL1)
BEGIN
INSERT INTO AuditTable VALUES (COL1, @prev, @next);
END;
FETCH NEXT FROM institution_cursor INTO -- @Variables here
END
CLOSE institution_cursor
DEALLOCATE institution_cursor