【问题标题】:How to prevent only non-empty tables from being dropped using a DDL trigger?如何防止使用 DDL 触发器仅删除非空表?
【发布时间】:2013-02-06 23:12:56
【问题描述】:

如果其中有行,我想防止删除表。

我写道:

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

但是dropped table 出现语法错误。

如何追踪即将删除的表?

【问题讨论】:

  • 您好,欢迎来到 SO。能否请您编辑帖子上的标签以显示您正在使用的 SQL 版本/类型(MS SQL、MySQL、Oracle 等)?这会让别人更容易回答。
  • 你从哪里得到这个dropped_table这个词?
  • 我没有 :)) 我猜到了,比如删除或插入。

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


【解决方案1】:

我认为您不能使用 DDL 触发器来执行此操作,因为在这种情况下,它是一个 after 触发器 - 因此该表不再存在,并且在系统元数据。为什么不只是防止删除所有表,而不仅仅是非空表?

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;

但这只会产生:

消息 208,第 16 级,状态 1,第 1 行
无效的对象名称“dbo.tablename”。

尽管如此,如果您在触发器中回滚,或者事务以其他方式中止,则该表随后会再次存在。就触发器本身而言,它并不存在。

【讨论】:

  • 谢谢。我不想阻止所有的掉落!对我没有意义。如果我打开交易,是否有助于解决您提到的问题?
  • 为什么只有在没有人插入任何数据的情况下才可以删除表?
  • 我不明白你的问题 - DROP TABLE 是一个隐式事务,并且在触发器触发之前对象仍然被丢弃,这样你就无法检查它是否为空,甚至尽管中止触发器本质上是回滚下降。在任何情况下,即使这很有帮助,如果您试图阻止其他人愚蠢地删除表,您如何期望他们总是用一个阻止它们运行的​​良好事务围绕他们被禁止的 DROP TABLE 语句?为什么不让他们自己检查桌子是否是空的?
猜你喜欢
  • 1970-01-01
  • 2021-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多