如何防止仅使用DDL触发器删除非空表?

时间:2013-02-06 23:12:56

标签: sql-server-2008 triggers ddl-trigger

如果有行,我想阻止丢弃表。

我写道:

create trigger prevDrop on database for drop_table
as
begin
   if exists (select * from dropped_table)
    raiserror('cant do',25,1)
end

但我的dropped table语法错误。

如何跟踪要删除哪个表?

1 个答案:

答案 0 :(得分:2)

我认为你不能用DDL触发器来做这件事,因为在这种情况下它是之后的触发器 - 所以表不再存在,并且在它中没有它的痕迹系统元数据。为什么不阻止丢弃所有表,而不仅仅是非空表?

CREATE TRIGGER prevDrop ON DATABASE
FOR DROP_TABLE
AS
BEGIN
  ROLLBACK;
  RAISERROR('Disable the trigger prevDrop to drop tables!',11,1);
END
GO

他们应该实施的是INSTEAD OF DDL triggers - 请在此投票:

http://connect.microsoft.com/SQLServer/feedback/details/243986

我还让他们更改了文档,这最初误导了人们相信DDL触发器阻止了操作,当它真的滚动它们时:

http://connect.microsoft.com/SQLServer/feedback/details/752210

我告诉你所有这一切的原因是因为你声明:

  

如何跟踪要删除哪个表?

但是这意味着您认为该表尚未删除。它有。你当然可以在DDL触发器中获取表名:

DECLARE @e XML = EVENTDATA(), @t NVARCHAR(513);

SET @t = @e.value('(/EVENT_INSTANCE/SchemaName)[1]', 'nvarchar(255)');
   + '.' + @e.value('(/EVENT_INSTANCE/ObjectName)[1]', 'nvarchar(255)');

RAISERROR('%s has been dropped.', 11, 1, @t);

但这对你没有帮助。您无法检查表的内容,因为它已不存在。你可以徒劳地尝试做一些聪明的事情,比如:

DECLARE @sql NVARCHAR(MAX) = N'SELECT COUNT(*) FROM ' + @t;
EXEC sp_executesql @sql;

但这只会产生:

  

Msg 208,Level 16,State 1,Line 1
  无效的对象名称'dbo.tablename'。

即使如果您在触发器中回滚,或者事务以其他方式中止,该表也会在之后再次存在。就触发器本身而言,它不存在。