当源表中有复合主键时,如何在SQL Server中使用合并

当源表中有复合主键时,如何在SQL Server中使用合并,sql,sql-server,upsert,Sql,Sql Server,Upsert,我试图使用MERGE语句从源表更新目标表,但由于SQL试图更新或删除多条记录,因此出现错误。对于后台-我有一个“source”表,它本质上是一个滚动表,记录业务添加的每个数据实例-它只由一个自动递增的“record id”键控。“target”表只能有一个主键实例,即“string”。其思想是查看源表——如果主键匹配,则使用新数据更新所述行,如果不匹配,则插入新行中的所有信息。问题是,我不断收到错误,我试图更新或删除相同的记录两次。我认为这是因为在源表中确实有两个(或更多)字符串实例(主键)。唯

我试图使用MERGE语句从源表更新目标表,但由于SQL试图更新或删除多条记录,因此出现错误。对于后台-我有一个“source”表,它本质上是一个滚动表,记录业务添加的每个数据实例-它只由一个自动递增的“record id”键控。“target”表只能有一个主键实例,即“string”。其思想是查看源表——如果主键匹配,则使用新数据更新所述行,如果不匹配,则插入新行中的所有信息。问题是,我不断收到错误,我试图更新或删除相同的记录两次。我认为这是因为在源表中确实有两个(或更多)字符串实例(主键)。唯一的区别是“添加日期”字段。我如何重新编写此文件以合并这两者?我对这个SQL函数非常陌生,我尝试了一些方法,但都返回了错误。所有这些都归功于另一个用户,他首先给了我合并的建议——我试图使用IF/THEN

我尝试在ON和MATCH子句中使用MAX record date,由于语法原因,这两个子句都返回了错误

MERGE 
    SCM_Top_Up_Operational O 
    USING SCM_Top_Up_Rolling 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);
下面是一些示例数据。如果我查询scm_top_up_rolling for string in('B418496220','B111116220'),我会得到以下结果:

RECORD_ID   String     Date_Added Real_Exfact Article_ID Excess_Top_Up                           Plant
----------- ---------- ---------- ----------- ---------- --------------------------------------- -----
3108        B418496220 2019-02-25 2019-05-15  B41849     1235                                    6220
3211        B418496220 2019-03-28 2019-03-28  B41849     1                                       6220
3212        B111116220 2019-03-28 2019-03-28  B11111     1                                       6220
现在,如果我查询scm\u top\u up\u operational以获得相同的字符串:

String     Date_Added Real_Exfact Article_ID Excess_Top_Up                           Plant
---------- ---------- ----------- ---------- --------------------------------------- -----
B418496220 2019-02-25 2019-05-15  B41849     1235                                    6220
我的目标是使用B418496220的最新条目更新scm_top_up_operational,因为它已经存在于operation表中。然后我想插入B111116220的新记录,因为它在操作表中不存在


希望对您有所帮助,谢谢。

您不能在合并语句中直接使用SCM\u Top\u Up\u Rolling,因为用于连接的键(即字符串)需要是唯一的

您需要做的是通过在merge语句的顶部添加几层CTE(公共表表达式)来准备源数据。此步骤的目的是删除重复项并返回唯一的行列表

请看下面的解决方案:

;with cte
as
(
    select String, Date_Added, Real_Exfact, Article_ID, Excess_Top_Up, Plant
        , row_number() over (partition by String order by Date_Added desc) as 'rank'
    from dbo.SCM_Top_Up_Rolling
)
, cte_source
as
(
    select *
    from cte
    where rank = 1
)
merge SCM_Top_Up_Operational O 
using cte_source 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);
查询的关键组件是窗口功能:

row_number()(按日期按字符串顺序划分)作为“秩”

这将生成一个新列排名

String     Date_Added   rank    
----------------------------    
B418496220 2019-02-25   2
B418496220 2019-03-28   1       <= To be used in the merge, e.g. where rank = 1
B111116220 2019-03-28   1       <= To be used in the merge, e.g. where rank = 1

希望答案足够清楚。祝您好运。

您可能对表格设计有问题,或者数据处理要求不明确。如果您同时包含表模式和一些示例数据,这将帮助其他人帮助您。我正在添加上面的模式-感谢您的回复添加模式导致我超过了字符数-但我确实添加了一些示例数据
merge SCM_Top_Up_Operational O 
using cte_source R              on (O.String = R.String)