Подтвердить что ты не робот

Несколько предложений 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.

4b9b3361

Ответ 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" в зависимости от того, что он делает.

Производительность не требует особого внимания, особенно если это не пользовательский процесс.

СОВЕТ. Сначала выполните обновление, а второе. В противном случае при первом загрузке вы получите одну запись вставки и одну запись обновления для каждой импортируемой строки.