SQL 根据 ApplicationTable 中的更新和插入触发 Update/Insert 到 logTable
SQL Trigger to Update/Insert to logTable based on Updates and Inserts in ApplicationTable
我四处寻找了很多,但还没有找到我要找的东西。抱歉,如果这是一个重复的问题,我没有看到符合我需求的问题。
我有一个包含 2 列 [UserID]
和 [RoleID]
的应用程序 Table [UserInRoles]
。该应用程序通过为新用户插入和在用户切换到不同角色时进行更新来管理此 table。
我有一个历史 Table [UserRoleHistory],它有 4 列 [UserID]
、[RoleID_New]
、[RoleID_Old]
、[DateOfChange]
我需要弄清楚的是如何创建一个触发器,每次 [UserInRoles].[RoleId]
更改时都会将新行插入 [UserRoleHistory]
。我希望将旧的 RoleId 存储在列 [RoleId_Old]
中,将新的 RoleId 存储在列 [RoleId_New]
中。此外,[UserId]
需要存储,GETDATE()
用于向 [DateOfChange]
添加值
此外,(这可能吗)我希望触发器在对应用程序进行插入时注意到 table [UserInRoles]
并保存数据 [UserId], [RoleId],GETDATE()
作为 [UserId], [RoleId_New] , GETDATE()
进入历史记录 Table 并保留 [RoleId_Old] as a null
值。
我对触发器还很陌生,不知道如何进行。如果我搞砸了,我没有删除触发器的权限,所以我还没有尝试创建一个。只是想先获得一些专家的意见。提前感谢所有花时间阅读本文并 answer/comment 的人。
****编辑****
我已经使用了你的建议,这就是我最终想出的。此触发器中包含我最初要求的更多信息,但在使用它后发现历史记录中我想要的信息 table 很容易获得,我按我认为合适的方式添加了它。
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
MSDN 创建触发器文档 (https://msdn.microsoft.com/en-GB/library/ms189799.aspx) 最后有一些方便的示例。我无耻地copy/pasted下面第一个作为例子:
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
这与您相关,因为它显示
- 如何在事务发生后触发触发器(特别是应该导致更改的事务 - 稍后会详细介绍)
- 之后如何发射你自己的sql。在您的情况下,这将插入另一个 table 而不是发送电子邮件。
- 向您展示如何 drop/re-create 触发器(如果它已经存在)(出于测试目的 - 假设您首先测试它,而不是直接应用到实时)。
如果您需要专门比较一个值以绝对确定该值已更改,那么在类似 here 上有一个先前的 post。本质上你写
INSTEAD OF INSERT
代替
AFTER INSERT
然后您可以根据需要执行任何条件逻辑或 CRUD 操作。
最后,因为您可以在触发器中弹出一个过程(如上所示),您可以为您将创建的任何触发器添加一些额外的复杂性,从而抽象出触发器本身中的任何逻辑。
注意:我使用了与您相同的 table 名称,所以不要 运行 使用实际的 table 对您的数据库进行此操作,因为我删除了它们。
试试这个。这将适用于任何更新、插入或删除。如果更改了 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 列 [UserID]
和 [RoleID]
的应用程序 Table [UserInRoles]
。该应用程序通过为新用户插入和在用户切换到不同角色时进行更新来管理此 table。
我有一个历史 Table [UserRoleHistory],它有 4 列 [UserID]
、[RoleID_New]
、[RoleID_Old]
、[DateOfChange]
我需要弄清楚的是如何创建一个触发器,每次 [UserInRoles].[RoleId]
更改时都会将新行插入 [UserRoleHistory]
。我希望将旧的 RoleId 存储在列 [RoleId_Old]
中,将新的 RoleId 存储在列 [RoleId_New]
中。此外,[UserId]
需要存储,GETDATE()
用于向 [DateOfChange]
此外,(这可能吗)我希望触发器在对应用程序进行插入时注意到 table [UserInRoles]
并保存数据 [UserId], [RoleId],GETDATE()
作为 [UserId], [RoleId_New] , GETDATE()
进入历史记录 Table 并保留 [RoleId_Old] as a null
值。
我对触发器还很陌生,不知道如何进行。如果我搞砸了,我没有删除触发器的权限,所以我还没有尝试创建一个。只是想先获得一些专家的意见。提前感谢所有花时间阅读本文并 answer/comment 的人。
****编辑**** 我已经使用了你的建议,这就是我最终想出的。此触发器中包含我最初要求的更多信息,但在使用它后发现历史记录中我想要的信息 table 很容易获得,我按我认为合适的方式添加了它。
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
MSDN 创建触发器文档 (https://msdn.microsoft.com/en-GB/library/ms189799.aspx) 最后有一些方便的示例。我无耻地copy/pasted下面第一个作为例子:
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
这与您相关,因为它显示
- 如何在事务发生后触发触发器(特别是应该导致更改的事务 - 稍后会详细介绍)
- 之后如何发射你自己的sql。在您的情况下,这将插入另一个 table 而不是发送电子邮件。
- 向您展示如何 drop/re-create 触发器(如果它已经存在)(出于测试目的 - 假设您首先测试它,而不是直接应用到实时)。
如果您需要专门比较一个值以绝对确定该值已更改,那么在类似 here 上有一个先前的 post。本质上你写
INSTEAD OF INSERT
代替
AFTER INSERT
然后您可以根据需要执行任何条件逻辑或 CRUD 操作。
最后,因为您可以在触发器中弹出一个过程(如上所示),您可以为您将创建的任何触发器添加一些额外的复杂性,从而抽象出触发器本身中的任何逻辑。
注意:我使用了与您相同的 table 名称,所以不要 运行 使用实际的 table 对您的数据库进行此操作,因为我删除了它们。
试试这个。这将适用于任何更新、插入或删除。如果更改了 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