SQL触发器根据应用程序表中的更新和插入更新/插入日志表

时间:2015-03-20 17:29:55

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

我做了很多环顾四周,还没找到我想要的东西。很抱歉,如果这是一个重复的问题,我没有看到符合我需求的问题。

我有一个应用程序表[UserInRoles],其中包含2列[UserID][RoleID]。当用户切换到其他角色时,应用程序使用Inserts for new Users和Updates管理此表。

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

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

此外,(这是可能的)我希望触发器在对应用程序表[UserInRoles]进行插入时注意并将数据[UserId], [RoleId],GETDATE()保存到历史记录中表格为[UserId], [RoleId_New] , GETDATE()并保留[RoleId_Old] as a null值。

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

**** **** EDIT 我已经使用了你的建议,这就是我最终提出的建议。这个触发器有一些我最初要求的信息,但在使用它之后发现历史表中我想要的信息很容易找到,我按照我认为合适的方式添加了它。

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

2 个答案:

答案 0 :(得分:1)

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. 显示如何删除/重新创建触发器(如果它已经存在)(用于测试目的 - 假设您首先测试它,而不是直接应用于实时)。
  4. 如果您需要专门比较某个值以确保该值已更改,那么之前的帖子类似于here。 Essentialy你写

    INSTEAD OF INSERT
    

    代替

    AFTER INSERT
    

    然后你可以根据需要做任何条件逻辑或CRUD操作。

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

答案 1 :(得分: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