Как вставить несколько строк в слияние? - PullRequest
1 голос
/ 09 июля 2019

Как вставить несколько строк в слияние в SQL? Я использую MERGE INSERT и мне интересно, возможно ли добавить две строки одновременно? Под запросом, который я написал, но, как вы можете видеть, я хочу вставить оба логических значения для IsNew, также, когда оно не совпадает, я хочу добавить строку для IsNew = 1 и один IsNew = 0. Как мне этого добиться?

MERGE ITEMS AS TARGET
USING @table AS SOURCE
ON T.[ID]=S.ID
WHEN MATCHED THEN
    UPDATE SET 
        T.[Content] = S.[Content],
WHEN NOT MATCHED THEN
    INSERT (ID, Content, TIME, IsNew)
    VALUES (ID, TEXT, GETDATE(), 1),

Ответы [ 2 ]

1 голос
/ 09 июля 2019

Вы не можете сделать это напрямую с помощью оператора merge, но есть простое решение.

Предложение merge <merge_not_matched> (которое является insert...values|default values) может содержать только одну строку в целевой таблице для каждой строки в исходной таблице.
Это означает, что для ввода двух строк для каждого соответствия вам просто нужно изменить исходную таблицу - в этом случае это так же просто, как запрос перекрестного соединения.

Однако предложение <merge_matched> требует, чтобы только одна строка из источника могла соответствовать любой отдельной строке из целевого объекта, иначе вы получите следующую ошибку:

Оператор MERGE пытался ОБНОВИТЬ или УДАЛИТЬ одну и ту же строку более одного раза. Это происходит, когда целевая строка соответствует более чем одной исходной строке. Оператор MERGE не может ОБНОВИТЬ / УДАЛИТЬ одну и ту же строку целевой таблицы несколько раз. Уточните предложение ON, чтобы убедиться, что целевая строка соответствует не более чем одной исходной строке, или используйте предложение GROUP BY для группировки исходных строк.

Чтобы решить эту проблему, вам нужно будет добавить условие к when match, чтобы убедиться, что только одна строка из исходной таблицы обновляет целевую таблицу:

MERGE Items AS T
USING (
    SELECT Id, Text, GetDate() As Date, IsNew
    FROM @table
    -- adding one row for each row in source
    CROSS JOIN (SELECT 0 As IsNew UNION SELECT 1) AS isNewMultiplier
       ) AS S
    ON T.[ID]=S.ID
WHEN MATCHED AND S.IsNew = 1 THEN -- Note the added condition here
    UPDATE SET 
        T.[Content] = S.[Text] 
WHEN NOT MATCHED THEN
    INSERT (Id, Content, Time, IsNew) VALUES 
    (Id, Text, Date, IsNew);

Вы можете увидеть живое демо на rextester.

Учитывая все вышесказанное, я хотел бы отослать вас к другому сообщению stackoverflow , которое предлагает лучшую альтернативу, чем использование оператора merge.
Автором ответа является Microsoft MVP и эксперт по базам данных SQL Server, вам следует хотя бы прочитать то, что он говорит.

0 голосов
/ 09 июля 2019

Кажется, вы не можете достичь этого, используя оператор слияния.Для вас может быть лучше разделить эти два запроса на обновление и вставить.

Например:

UPDATE ITEMS SET ITEMS.ID = @table.ID FROM ITEMS INNER JOIN @table ON ITEMS.ID = @table.ID

INSERT INTO ITEMS (ID, Content, TIME, IsNew) SELECT (ID, TEXT, GETDATE(), 1) FROM @table
INSERT INTO ITEMS (ID, Content, TIME, IsNew) SELECT (ID, TEXT, GETDATE(), 0) FROM @table

При этом обе строки будут вставлены по желанию, имитируя оператор слияния.Тем не менее, ваше заявление об обновлении не будет иметь большого значения - если вы сопоставляете на основе идентификатора, то вы не можете иметь какие-либо идентификаторы для обновления.Если вы хотите обновить другие поля, вы можете изменить его следующим образом:

UPDATE ITEMS SET ITEMS.Content = @table.TEXT FROM ITEMS INNER JOIN @table ON ITEMS.ID = @table.ID
...