SQL Server中源表含重复主键值时的MERGE语句改写求助
解决MERGE语句因源表重复主键报错的问题
这问题我刚学SQL的时候也踩过坑!核心原因很明确:你的源表SCM_Top_Up_Rolling里同一个String主键对应了多条记录(比如示例里的B418496220有两条),当MERGE匹配到目标表的同一条记录时,数据库不知道该用源表的哪条来更新,所以抛出了“尝试更新或删除多条记录”的错误。
你的需求是取每个String的最新记录(Date_Added最大)来做更新/插入,所以解决思路是先对源表做预处理,只保留每个String的最新数据,再用这个预处理后的数据集做MERGE。
方案1:用窗口函数筛选最新记录(推荐)
用ROW_NUMBER()窗口函数给每个String分组内的记录按Date_Added降序编号,只取编号为1的最新记录:
MERGE SCM_Top_Up_Operational O USING ( SELECT * FROM ( SELECT String, Date_Added, Real_Exfact, Article_ID, Excess_Top_Up, Plant, -- 给每个String的记录按Date_Added倒序编号,最新的行号为1 ROW_NUMBER() OVER (PARTITION BY String ORDER BY Date_Added DESC) AS rn FROM SCM_Top_Up_Rolling ) t WHERE t.rn = 1 -- 只保留每个String的最新记录 ) R ON (O.String = R.String) WHEN MATCHED THEN UPDATE SET O.Date_Added = R.Date_Added, O.Real_Exfact = R.Real_Exfact, O.Excess_Top_Up = R.Excess_Top_Up WHEN NOT MATCHED BY TARGET THEN INSERT ( String, Date_Added, Real_Exfact, Article_ID, Excess_Top_Up, Plant) VALUES (R.String, R.Date_Added, R.Real_Exfact, R.Article_ID, R.Excess_Top_Up, R.Plant);
方案2:用自增RECORD_ID筛选最新记录
因为你的源表RECORD_ID是自增主键,最新的记录必然对应最大的RECORD_ID,也可以用这个逻辑来筛选:
MERGE SCM_Top_Up_Operational O USING ( SELECT R.* FROM SCM_Top_Up_Rolling R INNER JOIN ( -- 先找出每个String对应的最大RECORD_ID SELECT String, MAX(RECORD_ID) AS max_record_id FROM SCM_Top_Up_Rolling GROUP BY String ) t ON R.String = t.String AND R.RECORD_ID = t.max_record_id ) R ON (O.String = R.String) WHEN MATCHED THEN UPDATE SET O.Date_Added = R.Date_Added, O.Real_Exfact = R.Real_Exfact, O.Excess_Top_Up = R.Excess_Top_Up WHEN NOT MATCHED BY TARGET THEN INSERT ( String, Date_Added, Real_Exfact, Article_ID, Excess_Top_Up, Plant) VALUES (R.String, R.Date_Added, R.Real_Exfact, R.Article_ID, R.Excess_Top_Up, R.Plant);
执行后效果
按你的示例数据,执行后目标表会变成:
B418496220会被更新为源表中Date_Added=2019-03-28的最新记录- 目标表不存在的
B111116220会被完整插入
内容的提问来源于stack exchange,提问作者XCCH004
相关产品推荐
相关产品推荐

