SQL Server MERGE语句存在的问题

18

源表

Id, Name, Address
1   A     #202
1   A     #203
1   A     #204
2   A     #202

目标表

Id, Name, Address
1   A     NULL

合并后
Id, Name, Address
1   A     #202
2   A     #202

我正在使用这个SQL语句

create table #S   (ID int, Name varchar(25) NULL, Address varchar(25) NULL)
create table #T   (ID int, Name varchar(25) NULL, Address varchar(25) NULL)

 INSERT #S values(1, 'A', '#202')
 INSERT #S values(1, 'A', '#203')
 INSERT #S values(1, 'A', '#203')
 INSERT #S values(1, 'A', '#204')

 INSERT #T values(1, 'A', NULL)

 MERGE #T USING
  (
Select id, name, address 
from #S
  ) AS S(id,name,address)
 on #T.id=S.id and #T.Name=S.Name
 when not matched THEN
    INSERT values(S.id,S.Name, S.Address)
 when matched then
    update set Address = S.Address;
 GO 

 Select * from #T
 GO 

 Select * from #S
 GO 

这会导致错误

消息 8672,级别 16,状态 1,第 18 行
当目标行匹配多个源行时,MERGE 语句尝试更新或删除同一行超过一次。 MERGE 语句不能多次更新/删除目标表的同一行。请完善 ON 子句以确保目标行最多与一个源行匹配,或使用 GROUP BY 子句对源行进行分组。

我想用任意三个匹配值中的 Address 值来更新 A 中的行。该怎么做?

2个回答

24
任何一个在#S中的四个值都会匹配目标表的单行值(因为#S中的所有值都具有id = 1和name = 'A' - 因此它们都与目标表中的单行匹配),因此这个值将被更新四次 - 这就是错误所说的,它是绝对正确的。
你真正想要在这里实现什么??
你想将地址设置为源表中的第一个值吗?在你的子查询中使用TOP 1子句:
MERGE #T 
USING (SELECT TOP 1 id, name, address FROM #S) AS S
ON #T.id = S.id AND #T.Name = S.Name
WHEN NOT MATCHED THEN
    INSERT VALUES(S.id,S.Name, S.Address)
WHEN MATCHED THEN
    UPDATE SET Address = S.Address;

您是否想将地址设置为源表值的随机元素?在子选择中使用TOP 1ORDER BY NEWID()子句:

MERGE #T 
USING (SELECT TOP 1 id, name, address FROM #S ORDER BY NEWID()) AS S
ON #T.id = S.id AND #T.Name = S.Name
WHEN NOT MATCHED THEN
    INSERT VALUES(S.id,S.Name, S.Address)
WHEN MATCHED THEN
    UPDATE SET Address = S.Address;

如果你将四个源行匹配到一个目标行,你永远不会得到有用的结果-你需要知道你真正想要的是什么。
Marc

我想用三个匹配值中的任何一个地址值来更新A中的行。 - R.D
3
但是如何确定使用它们中的哪一个? - HLGEM
2
我在使用Row_Number作为源和目标(视图)。然后匹配条件包括附加条件,如果行号相等且(target.address为空或(t.address = s.address)) - R.D
@marc 我有同样的问题,但还有额外的要求。我想更新来自源的最后一个值,并且我的源表包括另一个字段“street”,它的值将是s1、s2、s3、s4。在更新完成后,我想要获取这个结果 A s1、A s2、A s3、A s4,以便在另一个更新语句中使用这些数据。有什么想法吗? - user123456
这种方法并不适用于所有情况。如果源数据中包含您需要传输到目标地的审计日志信息,那么单独选择一行记录如何解决问题呢? - Sujith

1
使用

标签删除重复内容。

select R.* 
from  (SELECT Customer,Material,Received_date_time,
row_number() over (Partition by Customer, Material   
order by  Customer,Material,Received_date_time) as rn
      from Customer_Table WHERE Status=0     
     ) as R
where R.rn = 1

合并时不能有重复项,因此您始终需要选择最新的内容。


根据情况,这样做更有意义。也许您可以添加唯一约束。 - Akira Yamamoto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接