O Query Optimizer faz uma análise estática do seu lote T-SQL e, assim que vir a instrução MERGE, ele validará os requisitos. Ele NÃO levará em consideração nenhuma instrução DDL que afete os gatilhos antes da instrução MERGE.
Você pode contornar isso usando GO para dividir as instruções em lotes separados, mas se estiver em um único SP (sem instruções GO), você tem duas opções
- coloque o MERGE em um SP de suporte que o principal chama; ou
- usar SQL dinâmico
SQL Dinâmico
Vamos criar uma tabela com um gatilho
create table tg1(i int)
;
create trigger tg1_tg on tg1 instead of insert as
select 1
GO
Em seguida, tente MERGE na mesa
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
;
Não é bom..
Então usamos SQL dinâmico
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
;
Procedimento de suporte
Vamos criar um procedimento que irá realizar o MERGE (um proc de produção provavelmente teria uma variável de tabela, usaria uma tabela #temp ou receberia alguns parâmetros)
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
Não vá...
Mesmo para criá-lo, você precisa desabilitar os triggers - então desabilite o trigger e crie o proc novamente - desta vez funcionará.
Finalmente, você pode executar este lote que funciona
alter table tg1 disable trigger tg1_tg
;
exec tg1_MERGE
;
alter table tg1 enable trigger tg1_tg
;