有没有一种方法可以将信息传递到Delete触发器上,以便它可以知道谁删除了记录?
是的:通过使用一个非常酷(且使用不足的功能)的CONTEXT_INFO
。本质上,会话内存存在于所有作用域中,不受事务约束。它可用于传递信息(任何信息-好吧,适合有限空间的任何信息)以触发,以及在子proc / EXEC调用之间来回传递。我之前曾在完全相同的情况下使用过它。
测试以下内容以查看其工作方式。请注意,我转换成CHAR(128)
前CONVERT(VARBINARY(128), ..
。这是力空白填充,使其更容易转换回VARCHAR
得到它的时候CONTEXT_INFO()
,因为VARBINARY(128)
是右侧填充0x00
秒。
SELECT CONTEXT_INFO();
-- Initially = NULL
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), 'I deleted ALL your records! HA HA!')
);
SET CONTEXT_INFO @EncodedUser;
SELECT CONTEXT_INFO() AS [RawContextInfo],
RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())) AS [DecodedUser];
结果:
0x492064656C6574656420414C4C20796F7572207265636F7264732120484120484121202020202020...
I deleted ALL your records! HA HA!
全部放在一起:
应用程序应调用“删除”存储过程,该过程将传入正在删除记录的UserName(或其他名称)。我认为这已经是使用的模型,因为听起来您已经在跟踪插入和更新操作。
“删除”存储过程可以:
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), @UserName)
);
SET CONTEXT_INFO @EncodedUser;
-- DELETE STUFF HERE
审核触发器执行以下操作:
-- Set the INT value in LEFT (currently 50) to the max size of [UserWhoMadeChanges]
INSERT INTO AuditTable (IdOfRecordedAffected, UserWhoMadeChanges)
SELECT del.ID, COALESCE(
LEFT(RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())), 50),
'<unknown>')
FROM DELETED del;
请注意,正如@SeanGallardy在评论中指出的那样,由于其他过程和/或临时查询会从该表中删除记录,因此有可能:
CONTEXT_INFO
尚未设置,仍然为NULL
:
因此,我已经更新了上面的内容INSERT INTO AuditTable
以使用a COALESCE
作为默认值。或者,如果您不希望使用默认值并且需要一个名称,则可以执行以下操作:
DECLARE @UserName VARCHAR(50); -- set to the size of AuditTable.[UserWhoMadeChanges]
SET @UserName = LEFT(RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())), 50);
IF (@UserName IS NULL)
BEGIN
ROLLBACK TRAN; -- cancel the DELETE operation
RAISERROR('Please set UserName via "SET CONTEXT_INFO.." and try again.', 16 ,1);
END;
-- use @UserName in the INSERT...SELECT
CONTEXT_INFO
设置的值不是有效的用户名,因此可能会超出AuditTable.[UserWhoMadeChanges]
字段的大小:
因此,我添加了一个LEFT
函数,以确保从中抓取的所有内容CONTEXT_INFO
都不会破坏INSERT
。如代码中所述,您只需将设置50
为UserWhoMadeChanges
字段的实际大小。
SQL SERVER 2016及更高版本的更新
SQL Server 2016添加了此每个会话内存的改进版本:会话上下文。新的会话上下文实质上是键-值对的哈希表,其中“键”的类型为sysname
(即NVARCHAR(128)
),“值”的类型为SQL_VARIANT
。含义:
- 现在存在价值分离,因此不太可能与其他用途冲突
- 您可以存储各种类型,不再需要担心通过取回值时的奇怪行为
CONTEXT_INFO()
(有关详细信息,请参阅我的文章:为什么CONTEXT_INFO()不返回SET CONTEXT_INFO设置的确切值?)
- 你得到了很多更多的空间:8000字节每“价值”最高,可达所有按键256KB总(与128的最大字节
CONTEXT_INFO
)
有关详细信息,请参见以下文档页面:
SUSER_SNAME()
是获取删除记录的人的关键。