Инструкция SQL Server 2008 MERGE - как отключить триггер INSTEAD OF INSERT, чтобы разрешить MERGE - PullRequest
4 голосов
/ 02 февраля 2011

Я пытаюсь использовать оператор SQL SERVER 2008 MERGE в хранимой процедуре для обновления / вставки таблицы.У меня есть триггер INSTEAD OF INSERT в таблице, и я получаю следующее сообщение об ошибке при попытке СОЗДАТЬ процедуру

Целевой «Телефон» оператора MERGE имеет триггер INSTEAD OF в некоторых,но не все действия, указанные в операторе MERGE.В операторе MERGE, если какое-либо действие имеет включенный триггер INSTEAD OF на цели, тогда все действия должны включать триггеры INSTEAD OF.

Мне определенно не нужен триггер INSTEAD OF UPDATE, (ине могу создать его из-за того, что CASCADE DELETES включен для таблицы).

Поэтому в хранимой процедуре я сначала запускаю команду DISABLE TRIGGER перед MERGE.Но когда я запускаю сохраненный процесс, я получаю ту же ошибку, как если бы команда DISABLE TRIGGER никогда не запускалась.

1 Ответ

7 голосов
/ 02 февраля 2011

Оптимизатор запросов выполняет статический анализ вашего пакета T-SQL, и, как только он видит инструкцию MERGE, он проверяет требования. Он НЕ учитывает какие-либо операторы DDL, которые влияют на триггеры до оператора MERGE.

Вы можете обойти это, используя 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

Затем попытайтесь MERGE на столе

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
;

Не хорошо ..

Сообщение 5316, Уровень 16, Состояние 1, Строка 1
У цели 'tg1' оператора MERGE есть триггер INSTEAD OF для некоторых, но не для всех действий, указанных в операторе MERGE. В операторе 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

Не идти ...

Сообщение 5316, Уровень 16, Состояние 1, Строка 1
У цели 'tg1' оператора MERGE есть триггер INSTEAD OF для некоторых, но не для всех действий, указанных в операторе MERGE. В операторе MERGE, если какое-либо действие имеет включенный триггер INSTEAD OF на цели, тогда все действия должны включать триггеры INSTEAD OF.

Даже для его создания необходимо отключить триггеры - поэтому отключите триггер и создайте процедуру заново - на этот раз все будет работать.

Наконец, вы можете запустить этот пакет, который работает

alter table tg1 disable trigger tg1_tg
;
exec tg1_MERGE
;
alter table tg1 enable trigger tg1_tg
;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...