最简单的方法可能是简单地创建三个触发器 - 每个操作一个:
CREATE TRIGGER trgUserInsert
ON dbo.User AFTER INSERT
AS BEGIN
INSERT INTO dbo.UserHistory............
END
CREATE TRIGGER trgUserDelete
ON dbo.User AFTER DELETE
AS BEGIN
INSERT INTO dbo.UserHistory............
END
CREATE TRIGGER trgUserUpdate
ON dbo.User AFTER UPDATE
AS BEGIN
INSERT INTO dbo.UserHistory............
END
这样,事情变得简单,您可以轻松了解自己在做什么,此外,它还使您能够关闭单个操作的触发器,例如:需要插入或删除大量项目。
在触发器内部,您有两个“伪表”——Inserted(用于插入和更新)和Deleted(用于更新和删除)。这些伪表包含新插入的值(或 UPDATE 中的更新值),或已删除(用于 DELETE)或已更新的值(更新前的旧值,用于 UPDATE 操作)。
您需要注意,即使您更新大量行,触发器也会被调用一次,例如Inserted 和 Deleted 通常包含多行。
作为示例,您可以像这样编写“AFTER INSERT”触发器(只是猜测您的表结构可能是什么......):
CREATE TRIGGER trgUserInsert
ON dbo.User AFTER INSERT
AS BEGIN
INSERT INTO
dbo.UserHistory(UserID, Action, DateTimeStamp, AuditMessage)
SELECT
i.UserID, 'INSERT', getdate(), 'User inserted into table'
FROM
Inserted i
END
您正在寻找一种方法来找出此触发器导致的“动作”?我看不出有任何方法可以做到这一点 - 将三个触发器分开的另一个原因。找出这一点的唯一方法是计算Inserted 和Updated 表中的行数:
- 如果两个计数都大于零,则为
UPDATE
- 如果
Inserted 表有行,但Deleted 没有,则它是INSERT
- 如果
Inserted 表没有行,但Deleted 有,则它是DELETE
您还在寻找“已更新字段的列表”——同样,您不会有任何简单的解决方案,真的。您可以只遍历“用户”表中感兴趣的字段,然后检查
IF UPDATE(fieldname) ......
但这有点乏味。
或者您可以使用COLUMNS_UPDATED() 函数 - 但是,这不会为您提供一个很好的列名列表,而是一个 VARBINARY,其中每一列基本上都是一个位,如果它被打开,则该列已更新。不太好用.....
如果您真的想创建一个单一的大触发器,这可以作为基础 - 它检测导致触发器触发的操作,并将条目插入到您的 User_History 表中:
CREATE TRIGGER trgUser_Universal
ON dbo.Users
AFTER INSERT, UPDATE, DELETE
AS BEGIN
DECLARE @InsHasRows BIT = 0
DECLARE @DelHasRows BIT = 0
IF EXISTS(SELECT TOP 1 * FROM INSERTED)
SET @InsHasRows = 1
IF EXISTS(SELECT TOP 1 * FROM DELETED)
SET @DelHasRows = 1
DECLARE @TriggerAction VARCHAR(20)
IF @InsHasRows = 1 AND @DelHasRows = 1
SET @TriggerAction = 'UPDATE'
ELSE
IF @InsHasRows = 1
SET @TriggerAction = 'INSERT'
ELSE
SET @TriggerAction = 'DELETE'
IF @InsHasRows = 1
INSERT INTO dbo.UsersHistory(user_id, [action], [fields], timestamp)
SELECT i.UserId, @TriggerAction, null, getdate()
FROM INSERTED i
ELSE
INSERT INTO dbo.UsersHistory(user_id, [action], [fields], timestamp)
SELECT d.UserId, @TriggerAction, null, getdate()
FROM DELETED d
END
我还没有包括确定哪些字段已更新的部分 - 这留给读者作为练习:-)
这有帮助吗?