【问题标题】:SQL Server 2005: T-SQL to temporarily disable a triggerSQL Server 2005:T-SQL 临时禁用触发器
【发布时间】:2010-09-12 12:29:14
【问题描述】:

是否可以禁用一批命令的触发器,然后在批处理完成时启用它?

我确信我可以删除触发器并重新添加它,但我想知道是否还有其他方法。

【问题讨论】:

    标签: sql-server sql-server-2005 tsql


    【解决方案1】:
    DISABLE TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL }
    ON { object_name | DATABASE | ALL SERVER } [ ; ]
    

    http://msdn.microsoft.com/en-us/library/ms189748(SQL.90).aspx

    后跟逆:

    ENABLE TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL }
    ON { object_name | DATABASE | ALL SERVER } [ ; ]
    

    http://msdn.microsoft.com/en-us/library/ms182706(SQL.90).aspx

    【讨论】:

    • 谢谢!我认为我的 SQL Server 2005 天真在这个网站上表现得太好了。
    • 不用担心;做 DBA 很长一段时间,这些事情都会自动发生 :)
    • 即如果您使用选项修改触发器并且脚本包含ALTER TRIGGER [dbo].[trgWhatever] ON [dbo].[tblWhatever],那么您需要DISABLE TRIGGER [dbo].[trgWhatever] ON [dbo].[tblWhatever]ENABLE TRIGGER [dbo].[trgWhatever] ON [dbo].[tblWhatever]
    • 注意 - 我收到一个错误“‘禁用’附近的语法不正确。”除非我在PRINT 'Some message'; DISABLE TRIGGER [dbo]..... 之间放置一个;
    【解决方案2】:

    但是,这样做几乎总是一个坏主意。你会弄乱数据库的完整性。不要在没有考虑后果并与 dbas 核对是否有它们的情况下这样做。

    如果您确实遵循了 Matt 的代码,请务必记住重新打开触发器。并且请记住,触发器在关闭时对每个插入、更新或删除表的人都禁用,而不仅仅是您的进程,所以如果必须这样做,那么在数据库最不活跃的时间进行(最好是在单用户模式下)。

    如果您需要这样做来导入大量数据,请考虑批量插入不会触发触发器。但是,批量插入之后的过程将不得不修复您引入的任何数据完整性问题,也不能触发触发器。

    【讨论】:

    • 好点。我需要这个的原因是在将数据从生产环境复制到测试环境时,一些 AK 被触发器重置,但另一个表中的相关列没有效仿。
    【解决方案3】:

    有时要从外部数据源填充空数据库或调试数据库中的问题,我需要禁用所有触发器和约束。 为此,我使用以下代码:

    禁用所有约束和触发器:

    sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
    sp_msforeachtable "ALTER TABLE ? DISABLE TRIGGER  all"
    

    启用所有约束和触发器:

    exec sp_msforeachtable @command1="print '?'", @command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"
    sp_msforeachtable @command1="print '?'", @command2="ALTER TABLE ? ENABLE TRIGGER  all"
    

    我前段时间在SQLServerCentral 上找到了该解决方案,但需要修改启用约束部分,因为原来的部分不能完全工作

    【讨论】:

      【解决方案4】:

      为了扩展马特的答案,这是MSDN 上给出的示例。

      USE AdventureWorks;
      GO
      DISABLE TRIGGER Person.uAddress ON Person.Address;
      GO
      ENABLE Trigger Person.uAddress ON Person.Address;
      GO
      

      【讨论】:

        【解决方案5】:

        另一种方法是有效地禁用触发器而不实际禁用它,使用一个包含在触发器中的附加状态变量。

        create trigger [SomeSchema].[SomeTableIsEditableTrigger] ON [SomeSchema].[SomeTable]
        for insert, update, delete 
        as
        declare
            @isTableTriggerEnabled bit;
        
        exec usp_IsTableTriggerEnabled -- Have to use USP instead of UFN for access to #temp
            @pTriggerProcedureIdOpt  = @@procid,    
            @poIsTableTriggerEnabled = @isTableTriggerEnabled out;
        
        if (@isTableTriggerEnabled = 0)
            return;
        
        -- Rest of existing trigger
        go
        

        对于状态变量,可以读取表中某种类型的锁控制记录(最好限制在当前会话的上下文中),使用 CONTEXT_INFO(),或使用特定临时表名称的存在(即已经限制了会话范围):

        create proc [usp_IsTableTriggerEnabled]
            @pTriggerProcedureIdOpt  bigint          = null, -- Either provide this
            @pTableNameOpt           varchar(300)    = null, -- or this
            @poIsTableTriggerEnabled bit             = null out
        begin
        
            set @poIsTableTriggerEnabled = 1; -- default return value (ensure not null)
        
            -- Allow a particular session to disable all triggers (since local 
            -- temp tables are session scope limited).
            --
            if (object_id('tempdb..#Common_DisableTableTriggers') is not null)
            begin
                set @poIsTableTriggerEnabled = 0;
                return;
            end
        
            -- Resolve table name if given trigger procedure id instead of table name.
            -- Google: "How to get the table name in the trigger definition"
            --
            set @pTableNameOpt = coalesce(
                 @pTableNameOpt, 
                 (select object_schema_name(parent_id) + '.' + object_name(parent_id) as tablename 
                   from sys.triggers 
                   where object_id = @pTriggerProcedureIdOpt)
            );
        
            -- Else decide based on logic involving @pTableNameOpt and possibly current session
        end
        

        然后禁用所有触发器:

        select 1 as A into #Common_DisableTableTriggers;
        -- do work 
        drop table #Common_DisableTableTriggers; -- or close connection
        

        一个潜在的主要缺点是触发器会根据访问状态变量的复杂性而永久减慢。

        编辑:添加对这个惊人相似的2008 post by Samuel Vanga 的引用。

        【讨论】:

          【解决方案6】:
          ALTER TABLE table_name DISABLE TRIGGER TRIGGER_NAME
          -- Here your SQL query
          ALTER TABLE table_name ENABLE TRIGGER TRIGGER_NAME
          

          【讨论】:

            【解决方案7】:

            不是批处理编程的最佳答案,但对于其他人发现此问题以寻找一种快速简便的方法来临时禁用触发器,这可以在 SQL Server Management Studio 中完成。

            1. 展开表上的触发器文件夹
            2. 右键单击触发器
            3. 禁用

            按照相同的流程重新启用。

            【讨论】:

              猜你喜欢
              • 2023-04-07
              • 1970-01-01
              • 2010-09-07
              • 2013-05-25
              • 2010-09-14
              • 2011-04-05
              • 2012-11-11
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多