Несколько предложений OUTPUT в командах SQL MERGE/INSERT/DELETE?
У меня есть T-SQL
script, который реализует некоторую логику синхронизации, используя предложение OUTPUT
в MERGE
и INSERT
s.
Теперь я добавляю над ним уровень журналирования, и я хотел бы добавить второе предложение OUTPUT
, чтобы записать значения в таблицу отчетов.
Я могу добавить второе предложение OUTPUT
в мой оператор MERGE
:
MERGE TABLE_TARGET AS T
USING TABLE_SOURCE AS S
ON (T.Code = S.Code)
WHEN MATCHED AND T.IsDeleted = 0x0
THEN UPDATE SET ....
WHEN NOT MATCHED BY TARGET
THEN INSERT ....
OUTPUT inserted.SqlId, inserted.IncId
INTO @sync_table
OUTPUT $action, inserted.Name, inserted.Code;
И это работает, но пока я пытаюсь добавить цель
INTO @report_table;
Я получаю следующее сообщение об ошибке до INTO
:
A MERGE statement must be terminated by a semicolon (;)
Я нашел аналогичный вопрос здесь, но это не помогло мне дальше, потому что поля, которые я собираюсь вставить, не перекрываются между двумя таблицами, и я не нахожу Не хотите изменять рабочую синхронизацию (если это возможно).
UPDATE:
После ответа Мартин Смит у меня возникла другая идея и переписал мой запрос следующим образом:
INSERT INTO @report_table (action, name, code)
SELECT M.Action, M.Name, M.Code
FROM
(
MERGE TABLE_TARGET AS T
USING TABLE_SOURCE AS S
ON (T.Code = S.Code)
WHEN MATCHED AND T.IsDeleted = 0x0
THEN UPDATE SET ....
WHEN NOT MATCHED BY TARGET
THEN INSERT ....
OUTPUT inserted.SqlId, inserted.IncId
INTO @sync_table
OUTPUT $action as Action, inserted.Name, inserted.Code
) M
К сожалению, этот подход тоже не сработал, следующее сообщение об ошибке выводится во время выполнения:
An OUTPUT INTO clause is not allowed in a nested INSERT, UPDATE, DELETE, or MERGE statement.
Таким образом, нет определенного способа иметь несколько предложений OUTPUT
в одном заявлении DML.
Ответы
Ответ 1
Невозможно. См. Грамматику .
Оператор Merge имеет
[ <output_clause> ]
Квадратные скобки показывают, что он может иметь необязательное предложение вывода. Грамматика для этого
<output_clause>::=
{
[ OUTPUT <dml_select_list> INTO { @table_variable | output_table }
[ (column_list) ] ]
[ OUTPUT <dml_select_list> ]
}
Этот раздел может иметь как OUTPUT INTO
, так и OUTPUT
, но не два одинаковых.
Если множественное число было разрешено, грамматика имела бы [ ,...n ]
Ответ 2
Мартин Смит прав, в одном выражении MERGE
нельзя иметь два предложения OUTPUT INTO
, но он также прав, что может иметь один OUTPUT INTO
и один OUTPUT
. OUTPUT INTO
вставляет свой результирующий набор непосредственно в данную таблицу, а простой OUTPUT
возвращает результат, назначенный вызывающему.
Итак, вы можете обернуть оператор MERGE
в хранимую процедуру, а затем использовать INSERT ... EXEC
для вставки набора результатов простого OUTPUT
во вторую таблицу.
CREATE PROCEDURE [dbo].[TestMerge]
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
MERGE TABLE_TARGET AS T
USING TABLE_SOURCE AS S
ON (T.Code = S.Code)
WHEN MATCHED AND T.IsDeleted = 0x0
THEN UPDATE SET ....
WHEN NOT MATCHED BY TARGET
THEN INSERT ....
OUTPUT inserted.SqlId, inserted.IncId
INTO sync_table
OUTPUT $action AS MergeAction, inserted.Name, inserted.Code;
END
Использование
INSERT INTO report_table
EXEC [dbo].[TestMerge];
Это вставляет строки в sync_table
и в report_table
.
Если вы посмотрите план выполнения, вы увидите, что INSERT ... EXEC
создает временную таблицу за кулисами (см. также Скрытые затраты INSERT EXEC по
Адам Мачаник).
Ответ 3
Извините, что воскресил старый поток, но я просто столкнулся с этой проблемой и использовал решение, которое практично, а не техническое, и может быть или не быть очевидным.
Как уже обсуждалось, MERGE не предназначен для этого. Решение INSERT_INTO... EXEC является хорошим решением, но конкретная хранимая процедура, над которой я работаю, уже достаточно сложна.
Итак, чтобы все было просто для следующего парня, который должен работать над этим кодом, я просто использовал два оператора MERGE... тот, который выполняет вставку, и тот, который выполняет обновление. В конце концов, нет закона, в котором говорится, что вы должны использовать только один. Я добавил столбец "действие" в таблицу протоколирования, в которую у меня есть оператор MERGE, вставляющий "Insert" или "Update" в зависимости от того, что он делает.
Производительность не требует особого внимания, особенно если это не пользовательский процесс.
СОВЕТ. Сначала выполните обновление, а второе. В противном случае при первом загрузке вы получите одну запись вставки и одну запись обновления для каждой импортируемой строки.