SQL Server 2008 MERGE语句 - 如何禁用INSTEAD OF INSERT触发器以允许MERGE

时间:2011-02-02 01:40:07

标签: sql sql-server sql-server-2008 triggers merge

我试图在存储过程中使用SQL SERVER 2008 MERGE语句来更新/插入表。 我在表上有一个INSTEAD OF INSERT触发器,尝试创建过程时出现以下错误消息

  

MERGE语句的目标'Phone'对某些人有一个INSTEAD OF触发器,   但不是全部,MERGE声明中指定的行动。在MERGE语句中,如果任何操作在目标上启用了INSTEAD OF触发器,则所有操作都必须启用INSTEAD OF触发器。

我绝对不需要INSTEAD OF UPDATE触发器(并且由于在表上启用了CASCADE DELETES而无法创建一个)。

因此,在存储过程中,我首先在MERGE之前发出DISABLE TRIGGER命令。但是当我运行存储过程时,我得到了同样的错误,好像DISABLE TRIGGER命令永远不会运行。

1 个答案:

答案 0 :(得分:7)

查询优化器对T-SQL批处理进行静态解析,一看到MERGE语句,就会验证需求。它不会考虑任何影响MERGE语句之前的触发器的DDL语句。

你可以使用GO来解决这个问题,将语句分成不同的批次,但如果它在一个SP(没有GO语句)中,你有两个选择

  • 将MERGE放入主要呼叫的支持SP中;或
  • 使用动态SQL

动态SQL

让我们创建一个带触发器的表

create table tg1(i int)
;
create trigger tg1_tg on tg1 instead of insert as 
select 1
GO

然后尝试在桌面上合并

alter table tg1 disable trigger tg1_tg
;
merge tg1 as target
using (select 1 union all select 3) as source (X) on target.i = source.x
when matched then
    delete
when not matched by target then
    insert (i) values (x)
output $action, inserted.*, deleted.*
;
alter table tg1 enable trigger tg1_tg
;

不好......

  

Msg 5316,Level 16,State 1,Line 1
  MERGE语句的目标'tg1'对MERGE语句中指定的某些操作(但不是全部)具有INSTEAD OF触发器。在MERGE语句中,如果任何操作在目标上启用了INSTEAD OF触发器,则所有操作都必须启用INSTEAD OF触发器。

所以我们使用动态SQL

alter table tg1 disable trigger tg1_tg
;
exec ('
merge tg1 as target
using (select 1 union all select 3) as source (X) on target.i = source.x
when matched then
    delete
when not matched by target then
    insert (i) values (x)
output $action, inserted.*, deleted.*
;')
alter table tg1 enable trigger tg1_tg
;

支持程序

让我们创建一个执行MERGE的过程(生成过程可能会有一个表变量,使用#temp表或接受一些参数)

create proc tg1_MERGE as
merge tg1 as target
using (select 1 union all select 3) as source (X) on target.i = source.x
when matched then
    delete
when not matched by target then
    insert (i) values (x)
output $action, inserted.*, deleted.*
;
GO

不要......

  

Msg 5316,Level 16,State 1,Line 1
  MERGE语句的目标'tg1'对MERGE语句中指定的某些操作(但不是全部)具有INSTEAD OF触发器。在MERGE语句中,如果任何操作在目标上启用了INSTEAD OF触发器,则所有操作都必须启用INSTEAD OF触发器。

即使要创建它,您也需要禁用触发器 - 因此请禁用触发器并再次创建proc - 这次会有效。

最后,你可以运行这个有效的批次

alter table tg1 disable trigger tg1_tg
;
exec tg1_MERGE
;
alter table tg1 enable trigger tg1_tg
;