当源 table 中有复合主键时如何在 SQL 服务器中使用 MERGE
How to Use MERGE in SQL Server when you have a compound primary key in the source table
我正在尝试使用 MERGE 语句从源 table 更新目标 table 但出现错误,因为 SQL 正在尝试更新或删除多个记录。对于背景 - 我有 'source' table 本质上是一个滚动 table,它记录了业务添加的每个数据实例 - 它仅由自动增量 'record id' 键控。 'target' table 只能有一次主键实例 - 即 'string'。这个想法是查看源 table - 如果主键匹配,则用新数据更新所述行,如果不匹配 - 插入新行中的所有信息。问题是我不断收到错误消息,提示我尝试更新或删除同一条记录两次。我相信这种情况正在发生,因为在源 table 中确实有两个(或更多)字符串(主键)实例。唯一的区别是 'date_added' 字段。我怎样才能重写这个以合并两者?我对这个 SQL 函数很陌生,我尝试了一些方法,但都是 return 错误。所有的功劳都归功于首先给我 MERGE 建议的另一个用户 - 我试图使用 IF/THEN.
我尝试在 ON 和 MATCH 子句中使用 MAX 记录日期,这两个子句都因语法return而出现错误
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 中查询 ('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_top_up_operational 相同的字符串,我会得到:
String Date_Added Real_Exfact Article_ID Excess_Top_Up Plant
---------- ---------- ----------- ---------- --------------------------------------- -----
B418496220 2019-02-25 2019-05-15 B41849 1235 6220
我的目标是 scm_top_up_operational 更新为 B418496220 的最新条目,因为它已经存在于操作 table 中。然后我想插入 B111116220 的新记录,因为它在操作 table 中不存在。
希望对您有所帮助,谢谢。
您不能在合并语句中直接使用 SCM_Top_Up_Rolling,因为用于连接的键(即字符串)必须是唯一的。
您需要做的是通过在合并语句之上添加几层 CTE(通用 Table 表达式)来准备源数据。此步骤的目的是删除重复项和 return 一个唯一的行列表。
看看下面的解决方案:
;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);
查询的关键组成部分是 window 函数:
row_number() over (partition by String order by Date_Added desc) as 'rank'
生成一个新列 rank:
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
一旦我们生成了一个唯一列表(即具有最新 Date_Added 的字符串列表),我们就可以使用此列表作为我们的合并源。
merge SCM_Top_Up_Operational O
using cte_source R on (O.String = R.String)
希望答案足够清楚。祝你好运。
我正在尝试使用 MERGE 语句从源 table 更新目标 table 但出现错误,因为 SQL 正在尝试更新或删除多个记录。对于背景 - 我有 'source' table 本质上是一个滚动 table,它记录了业务添加的每个数据实例 - 它仅由自动增量 'record id' 键控。 'target' table 只能有一次主键实例 - 即 'string'。这个想法是查看源 table - 如果主键匹配,则用新数据更新所述行,如果不匹配 - 插入新行中的所有信息。问题是我不断收到错误消息,提示我尝试更新或删除同一条记录两次。我相信这种情况正在发生,因为在源 table 中确实有两个(或更多)字符串(主键)实例。唯一的区别是 'date_added' 字段。我怎样才能重写这个以合并两者?我对这个 SQL 函数很陌生,我尝试了一些方法,但都是 return 错误。所有的功劳都归功于首先给我 MERGE 建议的另一个用户 - 我试图使用 IF/THEN.
我尝试在 ON 和 MATCH 子句中使用 MAX 记录日期,这两个子句都因语法return而出现错误
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 中查询 ('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_top_up_operational 相同的字符串,我会得到:
String Date_Added Real_Exfact Article_ID Excess_Top_Up Plant
---------- ---------- ----------- ---------- --------------------------------------- -----
B418496220 2019-02-25 2019-05-15 B41849 1235 6220
我的目标是 scm_top_up_operational 更新为 B418496220 的最新条目,因为它已经存在于操作 table 中。然后我想插入 B111116220 的新记录,因为它在操作 table 中不存在。
希望对您有所帮助,谢谢。
您不能在合并语句中直接使用 SCM_Top_Up_Rolling,因为用于连接的键(即字符串)必须是唯一的。
您需要做的是通过在合并语句之上添加几层 CTE(通用 Table 表达式)来准备源数据。此步骤的目的是删除重复项和 return 一个唯一的行列表。
看看下面的解决方案:
;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);
查询的关键组成部分是 window 函数:
row_number() over (partition by String order by Date_Added desc) as 'rank'
生成一个新列 rank:
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
一旦我们生成了一个唯一列表(即具有最新 Date_Added 的字符串列表),我们就可以使用此列表作为我们的合并源。
merge SCM_Top_Up_Operational O
using cte_source R on (O.String = R.String)
希望答案足够清楚。祝你好运。