El Optimizador de consultas realiza un análisis estático de su lote de T-SQL y, tan pronto como ve la instrucción MERGE, valida los requisitos. NO tendrá en cuenta ninguna declaración DDL que afecte los activadores antes de la declaración MERGE.
Puede solucionar esto usando GO para dividir las declaraciones en lotes separados, pero si está en un solo SP (sin declaraciones GO), tiene dos opciones
- poner el MERGE en un SP de soporte al que llama el principal; o
- usar SQL dinámico
SQL dinámico
Vamos a crear una tabla con un disparador
create table tg1(i int)
;
create trigger tg1_tg on tg1 instead of insert as
select 1
GO
Luego intenta FUSIONAR en la 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
;
No es bueno..
Así que 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
;
Procedimiento de soporte
Vamos a crear un procedimiento que realice la FUSIÓN (un proceso de producción probablemente tendría una variable de tabla, usaría una tabla #temp o tomaría algunos 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
No vayas...
Incluso para crearlo, debe deshabilitar los disparadores, así que deshabilite el disparador y cree el proceso nuevamente, funcionará esta vez.
Finalmente, puede ejecutar este lote que funciona
alter table tg1 disable trigger tg1_tg
;
exec tg1_MERGE
;
alter table tg1 enable trigger tg1_tg
;