Слияние SQL Server — вывод, возвращающий нулевые удаленные строки как вставленные

Я использую MERGE для синхронизации данных в таблице и вижу неправильное (для меня) поведение SQL Server. Когда я OUTPUT значения INSERTED.* и строка была удалена, команда MERGE возвращает строку со всеми NULL столбцами для каждой удаленной строки.

Например, возьмем эту схему:

CREATE TABLE tbl
(
    col1 INT NOT NULL,
    col2 INT NOT NULL
);

Я делаю первоначальную загрузку данных, и все 4 строки выводятся, как и ожидалось.

WITH data1 AS (
SELECT 1 [col1],1 [col2]
UNION ALL SELECT 2 [col1],2 [col2]
UNION ALL SELECT 3 [col1],3 [col2]
UNION ALL SELECT 4 [col1],4 [col2]
)
MERGE tbl t
USING data1 s
ON t.col1 = s.col1 AND t.col2 = s.col2
WHEN NOT MATCHED BY TARGET
    THEN INSERT (col1,col2) VALUES (s.col1,s.col2)
WHEN NOT MATCHED BY SOURCE
    THEN DELETE
OUTPUT INSERTED.*;

Теперь, скажем, я удаляю 2 строки из данных, которые я синхронизирую с таблицей (в моем CTE), и делаю то же самое MERGE, я вижу возвращенные 2 строки всех столбцов NULL.

WITH data1 as (
SELECT 1 [col1],1 [col2]
UNION ALL SELECT 2 [col1],2 [col2]
)
MERGE tbl t
USING data1 s
ON t.col1 = s.col1 AND t.col2 = s.col2
WHEN NOT MATCHED BY TARGET
    THEN INSERT (col1,col2) VALUES (s.col1,s.col2)
WHEN NOT MATCHED BY SOURCE
    THEN DELETE
OUTPUT INSERTED.*;

Для меня это кажется неправильным поведением, потому что A) я не делал этого для каких-либо удаленных строк и B) это создает впечатление, что я вставил эти 2 строки NULL в свою таблицу, чего я явно не делал. Кто-нибудь может пролить свет на происходящее?


person Sanders    schedule 11.09.2014    source источник
comment
используйте $action в предложении вывода, чтобы различать.   -  person Laurence    schedule 12.09.2014
comment
@Laurence Верно, но вопрос в том, почему SQL Server в первую очередь выводит удаления, когда я указываю только вставки.   -  person Sanders    schedule 12.09.2014
comment
Из руководства output_clause: Возвращает строку для каждой строки в target_table, которая обновляется, вставляется или удаляется в произвольном порядке. Это не очень интуитивно понятно, но делает то, что говорит. msdn.microsoft.com/en-us/library/bb510625.aspx. Чтобы понять почему, представьте, что вы можете, например, сказать OUTPUT deleted.*, $action, inserted.col1 as x, inserted.col2 as y   -  person Laurence    schedule 12.09.2014
comment
@Laurence Итак, они, по сути, выводят одну строку для каждого изменения (ins/up/del), и, поскольку я выбираю только вставленные столбцы, они пусты. Вы правы, это имеет смысл, но не очень интуитивно понятно.   -  person Sanders    schedule 12.09.2014


Ответы (1)


Из документации:

output_clause — возвращает строку для каждой строки в target_table, которая обновляется, вставляется или удаляется в произвольном порядке. $action можно указать в предложении output. $action — это столбец типа nvarchar(10), который возвращает одно из трех значений для каждой строки: «INSERT», «UPDATE» или «DELETE», в зависимости от действия, которое было выполнено с этой строкой.

Кажется, что SQL Server выводит одну строку для каждой измененной строки (путем вставки или удаления). Когда я указываю OUTPUT INSERTED.*, я действительно указываю только вставленные данные, которые являются нулевыми для двух измененных строк. Если я укажу OUTPUT INSERTED.col1 [InsCol1],INSERTED.col2 [InsCol2],DELETED.col1 [DelCol1],DELETED.col2 [DelCol2],$action, то смогу лучше увидеть картину происходящего.

Спасибо Лоуренсу за ваш комментарий.

person Sanders    schedule 11.09.2014