Sql server MERGE多次尝试更新或删除同一行
我正在尝试使用从以下网站获得的合并语句加载标准KimballSCD2维度: 除了处理新实体外,此merge语句是相同的。这将作为数据流中的直接插入进行处理。此问题只涉及同一业务密钥的多个版本 执行merge语句时,SQL返回错误: 味精8672,第16级,状态1,第3行Sql server MERGE多次尝试更新或删除同一行,sql-server,tsql,sql-merge,scd2,Sql Server,Tsql,Sql Merge,Scd2,我正在尝试使用从以下网站获得的合并语句加载标准KimballSCD2维度: 除了处理新实体外,此merge语句是相同的。这将作为数据流中的直接插入进行处理。此问题只涉及同一业务密钥的多个版本 执行merge语句时,SQL返回错误: 味精8672,第16级,状态1,第3行 MERGE语句多次尝试更新或删除同一行。当目标行与多个源行匹配时,会发生这种情况MERGE语句不能多次更新/删除目标表的同一行。优化ON子句以确保目标行最多匹配一个源行,或使用GROUP BY子句对源行进行分组 我正在使用SQ
MERGE语句多次尝试更新或删除同一行。当目标行与多个源行匹配时,会发生这种情况
MERGE语句不能多次更新/删除目标表的同一行。优化ON子句以确保目标行最多匹配一个源行,或使用GROUP BY子句对源行进行分组 我正在使用SQL Server 2012: 源数据集 目标数据集 这就是我所期望的: 在下面,您可以找到重现问题的脚本:
CREATE TABLE SANDBOX.EHN.SOURCE_SCD2 (
BUSINESS_KEY BIGINT
,DESCRIPTION_A VARCHAR(2)
,M_CRC BIGINT
,StartDATE DATE
,EndDATE DATE )
CREATE TABLE SANDBOX.EHN.TARGET_SCD2 (
BUSINESS_KEY BIGINT
,DESCRIPTION_A VARCHAR(2)
,M_CRC BIGINT
,StartDATE DATE
,EndDATE DATE )
select *
from SANDBOX.EHN.TARGET_SCD2
truncate table SANDBOX.EHN.TARGET_SCD2
INSERT INTO SANDBOX.EHN.SOURCE_SCD2 VALUES (1, 'B', 1, '2015-05-16', '2015-06-01')
INSERT INTO SANDBOX.EHN.SOURCE_SCD2 VALUES (1, 'C', 2, '2015-06-01', '2015-06-11')
INSERT INTO SANDBOX.EHN.SOURCE_SCD2 VALUES (1, 'D', 3, '2015-06-11', '9999-12-31')
INSERT INTO SANDBOX.EHN.TARGET_SCD2 VALUES (1, 'A', 0, '2015-01-16', '9999-12-31')
INSERT INTO SANDBOX.EHN.TARGET_SCD2
SELECT BUSINESS_KEY
,DESCRIPTION_A
,M_CRC
,StartDATE
,EndDATE
FROM (
MERGE SANDBOX.EHN.TARGET_SCD2 D
USING SANDBOX.EHN.SOURCE_SCD2 UPD
ON(D.BUSINESS_KEY = UPD.BUSINESS_KEY )
WHEN MATCHED AND D.EndDATE = '9999-12-31'
THEN UPDATE SET D.EndDATE = UPD.EndDATE
OUTPUT $Action Action_Out, UPD.BUSINESS_KEY
, UPD.DESCRIPTION_A
, UPD.M_CRC
, UPD.StartDATE
, UPD.EndDATE
)AS MERGE_OUT
WHERE MERGE_OUT.Action_Out = 'UPDATE'
你能帮我解决这个问题吗?上次更新仅限使用
INSERT INTO SANDBOX.EHN.TARGET_SCD2
SELECT BUSINESS_KEY
,DESCRIPTION_A
,M_CRC
,StartDATE
,EndDATE
FROM (
MERGE SANDBOX.EHN.TARGET_SCD2 D
USING SANDBOX.EHN.SOURCE_SCD2 UPD
ON(D.BUSINESS_KEY = UPD.BUSINESS_KEY AND UPD.EndDATE = '9999-12-31')
WHEN MATCHED AND D.EndDATE = '9999-12-31'
THEN UPDATE SET D.EndDATE = UPD.StartDATE
OUTPUT $Action Action_Out, UPD.BUSINESS_KEY
, UPD.DESCRIPTION_A
, UPD.M_CRC
, UPD.StartDATE
, UPD.EndDATE
)AS MERGE_OUT
WHERE MERGE_OUT.Action_Out = 'UPDATE'
如果您希望目标表中的所有SRC行,那么我同意Nick.McDermaid
对于所有行使用
UPDATE TRG
SET TRG.EndDate = SRC.StartDATE
FROM SANDBOX.EHN.TARGET_SCD2 TRG
JOIN ( select SRC.BUSINESS_KEY, min(src.StartDATE)StartDATE
from SANDBOX.EHN.SOURCE_SCD2 SRC
group by SRC.BUSINESS_KEY
)SRC
on ( TRG.BUSINESS_KEY = SRC.BUSINESS_KEY
AND SRC.StartDate > TRG.StartDate )
where 1 = 1
INSERT SANDBOX.EHN.TARGET_SCD2
SELECT * FROM SANDBOX.EHN.SOURCE_SCD2
错误消息相当清楚:您有一个目标行,merge语句多次尝试更新或删除该行。这对于合并语句是不允许的。重写查询以确保一行只能作为一个update或delete语句的目标。感谢您的答复,但这正是问题所在,我们知道需要做什么,但不知道如何做?我有点困惑。。。AFAICT MERGE语句是顶级语句,不能像您现在这样在派生表中使用。至少我没有看到这种可能的用途。我在一个测试数据库(SS 2012)上执行了您的脚本,它给出了一条错误消息,我认为这是由于这个事实(包含合并的派生表开头“D”附近的语法不正确)。我遗漏了什么吗?
MERGE
对SCD的评价过高。我总是在事务中使用单独的插入/更新。有更多的代码和重复,但更容易调试。SCD更新的奇怪之处在于,源代码也是以日期分隔的。不仅是三个同时到达(而不是通常情况下的一个)。因此,您的案例并不常见,但可以实现。这不包括在任何在线的普通SCD建议中。不管怎样,我可以看到所需的SQL,如果你愿意,我可以发布,或者我可以更详细地解释。对不起,我没有时间对你的好奇心做出更详细的回应。但基本上,您可以在事务中用单独的update/insert语句替换merge。这里有一篇文章列出了合并的一些问题,尽管我不知道有多少仍然有效: