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

Jos*_*osh 4 sql sql-server merge triggers sql-server-2008

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

MERGE语句的目标"Phone"对MERGE语句中指定的某些操作(但不是全部)具有INSTEAD OF触发器.在MERGE语句中,如果任何操作在目标上启用了INSTEAD OF触发器,则所有操作都必须启用INSTEAD OF触发器.

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

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

Ric*_*iwi 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
Run Code Online (Sandbox Code Playgroud)

然后尝试在桌面上合并

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
;
Run Code Online (Sandbox Code Playgroud)

不好..

消息5316,级别16,状态1,行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
;
Run Code Online (Sandbox Code Playgroud)

支持程序

让我们创建一个执行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
Run Code Online (Sandbox Code Playgroud)

不行......

消息5316,级别16,状态1,行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
;
Run Code Online (Sandbox Code Playgroud)