我正在尝试创建一个执行三项操作的触发器: 1.防止删除特定表上的数据 2.为用户生成错误消息 3.记录尝试删除的数据以及SQL中的会话信息。
这是我到目前为止的代码:
CREATE TRIGGER [dbo].[MyTable_prevent_delete_and_audit]
ON [dbo].[MyTable]
INSTEAD OF DELETE AS
BEGIN
DECLARE @SESSIONINFO nvarchar(200)
SELECT @SESSIONINFO = (RTRIM(LTRIM(CAST(login_time as nvarchar(20)))) + ' '
+ RTRIM(LTRIM(hostname)) + ' ' + RTRIM(LTRIM(program_name)) + ' '
+ RTRIM(LTRIM(cmd)) + ' ' + RTRIM(LTRIM(loginame))) from sys.sysprocesses WHERE spid = @@SPID
INSERT INTO [dbo].[MyTable_AUDIT] ([Field1],[Field1],[SESSIONINFO])
SELECT [Field1],[Field1],@SESSIONINFO FROM deleted
RAISERROR ('Removing MyTable entries prevented by trigger. Contact your administrator', 16, 1)
END
RETURN
GO
上面的代码可以防止删除,并为用户引发错误。但是,没有任何内容输入审计表。如果我注释掉RAISEERROR行,则触发器会正确地将项目添加到审计表中,但当然会删除数据。我想我必须遗漏一些简单的东西(如果我提出错误就删除了吗?),或者误解了概念的某些元素。请告诉我我的方式错误! :)
编辑:Aaron Bertrand有正确的答案,我必须在提出错误之前提交我的审计数据。 RAISERROR基本上推回了所有内容,包括审计:
CREATE TRIGGER [dbo].[MyTable_prevent_delete_and_audit]
ON [dbo].[MyTable]
INSTEAD OF DELETE AS
BEGIN
DECLARE @SESSIONINFO nvarchar(200)
SELECT @SESSIONINFO = (RTRIM(LTRIM(CAST(login_time as nvarchar(20)))) + ' '
+ RTRIM(LTRIM(hostname)) + ' ' + RTRIM(LTRIM(program_name)) + ' '
+ RTRIM(LTRIM(cmd)) + ' ' + RTRIM(LTRIM(loginame))) from sys.sysprocesses WHERE spid = @@SPID
INSERT INTO [dbo].[MyTable_AUDIT] ([Field1],[Field1],[SESSIONINFO])
SELECT [Field1],[Field1],@SESSIONINFO FROM deleted
COMMIT TRANSACTION;
RAISERROR ('Removing MyTable entries prevented by trigger. Contact your administrator', 16, 1)
END
RETURN
GO
答案 0 :(得分:4)
尝试在提出错误之前提交INSERT
。否则,引发错误会回滚触发器所做的一切以及调用触发器的语句所做的一切。
INSERT INTO [dbo].[MyTable_AUDIT] ([Field1],[Field1],[SESSIONINFO])
SELECT [Field1],[Field1],@SESSIONINFO FROM deleted;
COMMIT TRANSACTION;
RAISERROR ('Removing MyTable entries prevented by trigger. ...', 16, 1);