【问题标题】:SQL Trigger to Update/Insert to logTable based on Updates and Inserts in ApplicationTableSQL 触发器根据 ApplicationTable 中的更新和插入更新/插入 logTable
【发布时间】:2015-05-24 05:09:48
【问题描述】:

我已经环顾四周,但还没有找到我正在寻找的东西。抱歉,如果这是一个重复的问题,我没有看到符合我需求的问题。

我有一个应用程序表[UserInRoles],它包含两列[UserID][RoleID]。当用户切换到不同的角色时,应用程序会使用新用户的插入和更新来管理此表。

我有一个历史记录表 [UserRoleHistory],它有 4 列 [UserID][RoleID_New][RoleID_Old][DateOfChange]

我需要弄清楚的是如何创建一个触发器,该触发器将在每次[UserInRoles].[RoleId] 更改时向[UserRoleHistory] 插入一个新行。我希望将旧 RoleId 存储在 [RoleId_Old] 列中,并将新 RoleId 存储在 [RoleId_New] 列中。还需要存储[UserId] 并使用GETDATE()[DateOfChange] 增加价值

另外,(这可能)我希望触发器能够注意到何时对应用程序表 [UserInRoles] 进行了插入并将数据 [UserId], [RoleId],GETDATE() 保存到历史表中为 @987654337 @ 并保留 [RoleId_Old] as a null 值。

我对触发器非常陌生,不知道如何继续。如果我搞砸了触发器,我没有权限删除它,所以我还没有尝试创建一个。只是想先获得一些专家意见。提前感谢所有花时间阅读和回答/评论此问题的人。

****编辑**** 我已经使用了你的建议,这就是我最终想出的。此触发器包含我最初要求的更多信息,但在使用它后发现我在历史记录表中想要的信息很容易获得,我按照我认为合适的方式添加了它。

CREATE TRIGGER [dbo].[UserInRoles_Insert_Delete_Update] ON [dbo].[UsersInRoles]
AFTER INSERT,DELETE,UPDATE
AS
    IF (SELECT COUNT(*) FROM inserted) > 0 
        BEGIN 
            IF (SELECT COUNT(*) FROM deleted) > 0 
                BEGIN 
                    -- update! 
                    INSERT INTO [dbo].[UserRole_History](WinNTLogin,UserID,RoleID_Old,RoleID_New,RoleName,DateOfChange,Operation)
                        SELECT  (select distinct[LoweredUserName] from [dbo].[Users] 
                                 where (inserted.UserId = Users.UserId) or (deleted.UserId = Users.UserId))
                                ,CASE
                                    WHEN inserted.UserID IS NOT NULL THEN inserted.UserID
                                    ELSE deleted.UserID
                                 END
                                ,deleted.RoleID
                                ,inserted.RoleID
                                ,(select distinct[RoleName] from [dbo].[Roles] 
                                  where (inserted.RoleId = Roles.RoleId) or (deleted.RoleId = Roles.RoleId))
                                ,GETDATE()
                                ,'U'
                        FROM inserted
                        FULL JOIN deleted
                        ON inserted.UserID = deleted.UserID
                END 
            ELSE 
                BEGIN 
                    -- insert!
                    INSERT INTO [dbo].[UserRole_History](WinNTLogin,UserID,RoleID_Old,RoleID_New,RoleName,DateOfChange,Operation)
                        SELECT  (select distinct[LoweredUserName] from [dbo].[Users] 
                                 where (inserted.UserId = Users.UserId) or (deleted.UserId = Users.UserId))
                                ,CASE
                                    WHEN inserted.UserID IS NOT NULL THEN inserted.UserID
                                    ELSE deleted.UserID
                                 END
                                ,deleted.RoleID
                                ,inserted.RoleID
                                ,(select distinct[RoleName] from [dbo].[Roles] 
                                  where (inserted.RoleId = Roles.RoleId) or (deleted.RoleId = Roles.RoleId))
                                ,GETDATE()
                                ,'I'
                        FROM inserted
                        FULL JOIN deleted
                        ON inserted.UserID = deleted.UserID
                END 
        END 
    ELSE 
        BEGIN 
            -- delete! 
            INSERT INTO [dbo].[UserRole_History](WinNTLogin,UserID,RoleID_Old,RoleID_New,RoleName,DateOfChange,Operation)
                        SELECT  (select distinct[LoweredUserName] from [dbo].[Users] 
                                 where (inserted.UserId = Users.UserId) or (deleted.UserId = Users.UserId))
                                ,CASE
                                    WHEN inserted.UserID IS NOT NULL THEN inserted.UserID
                                    ELSE deleted.UserID
                                 END
                                ,deleted.RoleID
                                ,inserted.RoleID
                                ,(select distinct[RoleName] from [dbo].[Roles] 
                                  where (inserted.RoleId = Roles.RoleId) or (deleted.RoleId = Roles.RoleId))
                                ,GETDATE()
                                ,'D'
                        FROM inserted
                        FULL JOIN deleted
                        ON inserted.UserID = deleted.UserID
        END
GO

【问题讨论】:

    标签: sql-server tsql triggers sql-server-2012 dynamic-sql


    【解决方案1】:

    注意:我使用了与您相同的表名,因此请勿使用实际表对您的数据库运行此操作,因为我删除了它们。

    试试这个。这适用于任何更新、插入或删除。如果 UserID 被更改(这可能不应该发生),那么它看起来就像插入了一个带有新 RoleID 的新 UserId。如果您还需要什么,请告诉我。

    --If the tables exist, delete them
    IF OBJECT_ID('UserInRoles') IS NOT NULL
        DROP TABLE UserInRoles;
    IF OBJECT_ID('UserRoleHistory') IS NOT NULL
        DROP TABLE UserRoleHistory;
    
    CREATE TABLE UserInRoles
    (
    UserID INT PRIMARY KEY,
    RoleID INT
    );
    GO
    
    CREATE TABLE UserRoleHistory
    (
    UserID INT,
    RoleID_Old INT,
    RoleID_New INT,
    DateOfChange DATETIME
    );
    GO
    
    CREATE TRIGGER trg_History ON UserInRoles
    AFTER INSERT,DELETE,UPDATE
    AS
        INSERT INTO UserRoleHistory(UserID,RoleID_Old,RoleID_New,DateOfChange)
            SELECT  CASE
                        WHEN inserted.UserID IS NOT NULL THEN inserted.UserID
                        ELSE deleted.UserID
                    END,
                    deleted.RoleID,
                    inserted.RoleID,
                    GETDATE()
            FROM inserted
            FULL JOIN deleted
            ON inserted.UserID = deleted.UserID
    GO
    
    INSERT INTO UserInRoles
    VALUES  (1,1);
    INSERT INTO UserInRoles
    VALUES  (2,1);
    INSERT INTO UserInRoles
    VALUES  (3,2);
    GO
    
    UPDATE UserInRoles
    SET RoleID = 111
    WHERE RoleID = 1;
    GO
    
    UPDATE UserInRoles
    SET RoleID = 222
    WHERE RoleID = 2;
    GO
    
    DELETE
    FROM UserInRoles
    WHERE UserID >= 1
    GO
    
    SELECT *
    FROM UserRoleHistory
    ORDER BY DateOfChange
    

    结果:

    UserID      RoleID_Old  RoleID_New  DateOfChange
    ----------- ----------- ----------- -----------------------
    1           NULL        1           2015-03-20 13:06:37.010
    2           NULL        1           2015-03-20 13:06:37.010
    3           NULL        2           2015-03-20 13:06:37.010
    2           1           111         2015-03-20 13:06:37.047
    1           1           111         2015-03-20 13:06:37.047
    3           2           222         2015-03-20 13:06:37.050
    3           222         NULL        2015-03-20 13:06:37.063
    2           111         NULL        2015-03-20 13:06:37.063
    

    【讨论】:

      【解决方案2】:

      MSDN 创建触发器文档 (https://msdn.microsoft.com/en-GB/library/ms189799.aspx) 最后提供了一些方便的示例。我无耻地复制/粘贴了下面的第一个作为示例:

      IF OBJECT_ID ('Sales.reminder2','TR') IS NOT NULL
      DROP TRIGGER Sales.reminder2;
      GO
      CREATE TRIGGER reminder2
      ON Sales.Customer
      AFTER INSERT, UPDATE, DELETE 
      AS
          EXEC msdb.dbo.sp_send_dbmail
          @profile_name = 'AdventureWorks2012 Administrator',
          @recipients = 'danw@Adventure-Works.com',
          @body = 'Don''t forget to print a report for the sales force.',
          @subject = 'Reminder';
      GO
      

      这与您相关,因为它显示

      1. 如何在事务发生后触发触发器(特别是应该导致更改的触发器 - 稍后会详细介绍)
      2. 之后如何启动您自己的 sql。在您的情况下,这将插入另一个表而不是发送电子邮件。
      3. 向您展示如何删除/重新创建已经存在的触发器(出于测试目的 - 假设您首先测试它,而不是直接应用到实时)。

      如果您需要专门比较一个值以绝对确定该值已更改,那么之前有一篇类似here 的帖子。基本上你写的

      INSTEAD OF INSERT
      

      代替

      AFTER INSERT
      

      然后您可以根据需要执行任何条件逻辑或 CRUD 操作。

      最后,因为您可以在触发器中弹出一个过程(如上所示),您可以为您将创建的任何触发器添加一些额外的复杂性,从而抽象出触发器本身中的任何逻辑。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-01
        • 1970-01-01
        相关资源
        最近更新 更多