50

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

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

4

7 回答 7

62
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

于 2008-09-23T20:14:26.647 回答
39

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

要禁用所有约束和触发器:

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上找到了该解决方案,但需要修改启用约束部分,因为原来的部分不能完全工作

于 2008-09-23T21:20:24.463 回答
16

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

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

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

于 2008-09-23T20:35:14.150 回答
12

为了扩展马特的答案,这里是MSDN上给出的一个例子。

USE AdventureWorks;
GO
DISABLE TRIGGER Person.uAddress ON Person.Address;
GO
ENABLE Trigger Person.uAddress ON Person.Address;
GO
于 2013-07-04T05:38:09.050 回答
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

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

编辑:添加对Samuel Vanga 2008 年这篇惊人相似的帖子的引用。

于 2013-10-02T23:53:43.213 回答
4
ALTER TABLE table_name DISABLE TRIGGER TRIGGER_NAME
-- Here your SQL query
ALTER TABLE table_name ENABLE TRIGGER TRIGGER_NAME
于 2016-08-19T09:30:14.507 回答
2

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

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

在此处输入图像描述

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

于 2017-09-09T18:00:06.283 回答