SQL Server触发器以防止数据库丢弃

时间:2016-12-09 16:34:49

标签: triggers sql-server-2012 eventtrigger

我想放置一个服务器级触发器,以防止丢弃任何非数据库快照的数据库。乍一看,下面看起来好像应该有效,但它永远不会。我试过逆转逻辑,这没有帮助。有谁知道我做错了什么?

DECLARE @DBName NVARCHAR(100),
        @eventData XML;

SET @eventData = EVENTDATA();           
SELECT  @DBName = @eventData.value('data(/EVENT_INSTANCE/DatabaseName)[1]', 'SYSNAME');

RAISERROR('Attempting delete of %s.', 10, 1, @DBName);

IF @DBName IN (SELECT name
               FROM sys.databases 
               WHERE source_database_id IS NOT NULL)
    BEGIN
        RAISERROR('[%s] was successfully dropped.', 10, 1, @DBname) WITH LOG;
    END;
ELSE         
    BEGIN
        RAISERROR('[%s] cannot be deleted without first disabling the server trigger "tgr_prevent_db_drop".', 10, 1, @DBname) WITH LOG;
        ROLLBACK;
    END;

顶部的RAISERROR始终确认正确的数据库(例如正在删除的数据库),当我从sys.databases手动运行SELECT时,它总是返回适当的数据。不幸的是,无论我做什么,这都属于真实数据库及其数据库快照的“成功删除”部分。

2 个答案:

答案 0 :(得分:1)

我也试过让它工作,但由于sys.databases只返回当前用户可见的值,因此遇到了太多的权限障碍。 (并且我无法获得足够可靠的通用解决方案"执行As"尝试。)

最后我决定使用数据库名称作为过滤器。例如:

DECLARE @DBName NVARCHAR(100),
        @eventData XML;

SET @eventData = EVENTDATA();           
SELECT  @DBName = @eventData.value('data(/EVENT_INSTANCE/DatabaseName)[1]', 'SYSNAME');

RAISERROR('Attempting delete of %s.', 10, 1, @DBName);

IF Right(@DBName, 9) <> '_SnapShot' --Checking via db name due to permissions affecting sys.databases
    BEGIN
        RAISERROR('[%s] was successfully dropped.', 10, 1, @DBname) WITH LOG;
    END;
ELSE         
    BEGIN
        RAISERROR('[%s] cannot be deleted without first disabling the server trigger "tgr_prevent_db_drop".', 10, 1, @DBname) WITH LOG;
        ROLLBACK;
    END;

答案 1 :(得分:0)

这种情况总是如此......

IF @DBName IN (SELECT name
               FROM sys.databases 
               WHERE source_database_id IS NOT NULL)
    BEGIN
        RAISERROR('[%s] was successfully dropped.', 10, 1, @DBname) WITH LOG;
    END;

所以,你的数据库无论如何都会被删除..而不是将else子句移到上面的块

RAISERROR('[%s] cannot be deleted without first disabling the server trigger "tgr_prevent_db_drop".', 10, 1, @DBname) WITH LOG;
        ROLLBACK;