为插入,修改和删除创建数据库触发器的正确​​语法是什么

时间:2010-01-06 16:58:43

标签: sql sql-server database triggers

我有一个似乎是SQL服务器中的数据库触发器的基本方案,我遇到了一个问题。

我有用户表(ID,姓名,电话等),我有表 UsersHistory (id,user_id操作,字段,时间戳)

我想要一个数据库触发器,随时随地插入,更新或删除用户,我想要在UsersHistory中创建一个新记录,其中包含用户ID和已完成的操作(插入新的,更新的字段,已删除的ID。基本上是审计日志表

这是我有多远,但我无法弄清楚如何:

  1. 获取修改和删除的ID以及
  2. 如何获取已更改的字段列表以及已提交的操作(插入,删除,更新)

  3. CREATE TRIGGER Update_Users_History 
       ON  Users
       AFTER INSERT,DELETE,UPDATE
     AS 
     BEGIN
    -- Insert statements for trigger here
    
    insert into UsersHistory (user_id, [action], [fields], timestamp)
    select  max(id) as user_id, {action ??},{fields??}  getdate() from Users)
    
    END
    GO
    

    有什么建议吗?

2 个答案:

答案 0 :(得分:10)

最简单的方法就是简单地创建三个触发器 - 每个操作一个:

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(用于INSERT和UPDATE)和Deleted(用于UPDATE和DELETE)。这些伪表包含新插入值(或UPDATE中更新的值)的值,或者已删除(对于DELETE)或已更新的值(更新前的旧值,UPDATE操作)。 / p>

您需要注意,即使您更新了大量行,也会调用一次触发器,例如: InsertedDeleted通常会包含多行。

作为一个示例,您可以像这样编写一个“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     

您正在寻找一种方法来找出此触发器引起的“操作”?我没有看到任何方法这样做 - 保持三个触发器分开的另一个原因。找到这个的唯一方法是计算InsertedUpdated表中的行:

  • 如果两个计数都大于零,则为UPDATE
  • 如果Inserted表包含行,但Deleted没有,则为INSERT
  • 如果Inserted表没有行,但Deleted表没有,则为DELETE

您还在寻找“已更新的字段列表” - 再次,您将无法获得任何简单的解决方案。您可以直接浏览“Users”表中感兴趣的字段,然后选中

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

我还没有包括弄清楚哪些字段已经更新了部分 - 这是留给读者的练习: - )


这有帮助吗?

答案 1 :(得分:2)

触发器中使用了两个“表”。一个是DELETED,一个是INSERTED。删除行时,该行将在DELETED表中捕获。插入行时,该行将在INSERTED表中捕获。更新行时,旧行位于DELETED表中,新行位于INSERTED表中。 DELETEDINSERTED表与添加触发器的表具有相同的模式。

您可以查看将为您创建查询的this solution,它将创建您想要的所有审核触发器,以及用于存储审核的表,不包括任何选定的表。它只会执行UPDATE个触发器,但也可以轻松修改,以便生成INSERTDELETE个触发器。