如何在合并中插入多行?

时间:2019-07-09 09:15:48

标签: sql-server tsql sql-merge

如何在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 个答案:

答案 0 :(得分:1)

您不能使用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);

You can see a live demo on rextester.

话虽如此,我想请您参考另一个stackoverflow post,它提供了比使用merge语句更好的选择。
答案的作者是Microsoft MVP和SQL Server专家DBA,您至少应该阅读他的话。

答案 1 :(得分:0)

似乎您无法使用merge语句实现此目的。您最好将两者拆分为单独的查询以进行更新和插入。

例如:

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

这将根据需要插入两行,从而模仿您的merge语句。但是,您的update语句不会做太多事情-如果您根据ID进行匹配,则不可能更新任何ID。如果您想更新其他字段,则可以这样更改:

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