我试图在存储过程中使用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命令永远不会运行。
答案 0 :(得分:7)
查询优化器对T-SQL批处理进行静态解析,一看到MERGE语句,就会验证需求。它不会考虑任何影响MERGE语句之前的触发器的DDL语句。
你可以使用GO来解决这个问题,将语句分成不同的批次,但如果它在一个SP(没有GO语句)中,你有两个选择
让我们创建一个带触发器的表
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
;