SQL Server 2005:T-SQL暂时禁用触发器

时间:2008-09-23 20:13:42

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

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

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

7 个答案:

答案 0 :(得分: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

答案 1 :(得分:32)

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

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

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找到了解决方案,但需要修改启用限制部分,因为原始部分无法完全运行

答案 2 :(得分:15)

但是,这样做几乎总是一个坏主意。你会搞乱数据库的完整性。如果没有考虑分支并检查dbas,请不要这样做。

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

如果您需要执行此操作以导入大量数据,请考虑批量插入不会触发触发器。但是,批量插入后的过程将不得不修复您引入的任何数据完整性问题,也不必触发触发器。

答案 3 :(得分:11)

为了扩展马特的答案,以下是MSDN给出的一个例子。

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

答案 4 :(得分: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的引用。

答案 5 :(得分:3)

ALTER TABLE table_name DISABLE TRIGGER TRIGGER_NAME
-- Here your SQL query
ALTER TABLE table_name ENABLE TRIGGER TRIGGER_NAME

答案 6 :(得分:2)

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

  1. 展开表格上的触发器文件夹
  2. 右键单击触发器
  3. 禁用
  4. enter image description here

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