首页 > 解决方案 > SQL Server 合并和 pk 冲突

问题描述

我试图理解为什么在如下情况下

DECLARE @source TABLE 
             (
                 orderId NVARCHAR(50),
                 customerId NVARCHAR(50)
             )

DECLARE @target TABLE 
             (
                  orderId NVARCHAR(50) PRIMARY KEY,
                  customerId NVARCHAR(50) NOT NULL
             )

INSERT INTO @source 
VALUES ('test', '123'), ('test', '234')

MERGE @target AS TRG
USING (SELECT DISTINCT orderId, customerId
       FROM @source) AS SRC ON SRC.orderId = TRG.orderId

WHEN MATCHED THEN
    UPDATE SET TRG.customerId = SRC.customerId

WHEN NOT MATCHED BY TARGET THEN
    INSERT (orderId, customerId)
    VALUES (orderId, customerId);

我收到重复的密钥违规错误:

消息 2627,级别 14,状态 1,第 21 行
违反主键约束“PK__#B3D7759__0809335D4BE1521F”。无法在对象“dbo.@target”中插入重复键。重复键值为 (test)。

我期望更新语句找到现有密钥并更新customerId,以便最后我在@target 1 行中有orderId = 'test' 和customerId = '234'。

对于我可以假设的情况,它会尝试插入所有记录,因为它首先在合并开始时没有找到任何键匹配,从而导致违规,因为源多次包含键。

这是正确的吗?有什么方法可以使用合并功能实现我的期望?


@user1443098

我已经阅读了你的链接,谢谢。但是,我有大量数据插入来自源表并进入 10 个不同的表;我尝试使用游标实现该过程,每条记录大约需要 0.5 秒(所有 if exists 语句)。使用 merge 语句,在不到一秒的时间内在 10 个不同的表中插入了 300 行。所以在我的情况下,它在性能方面有很大的不同。

标签: sql-servermergeprimary-key

解决方案


有两条@source相同的记录OrderID。中的任何一条记录都不匹配,@target因此该NOT MATCHED子句试图插入这两条记录。但它不能这样做,因为表OrderID中的主键@target要求所有插入的记录都具有唯一的值OrderID。将值复制到主键中会导致主键违规。

如果您期望源中可能出现重复...您应该在USING子查询中消除它们。像这样的东西:

(SELECT orderId, max(customerId) customerId
FROM @source
group by orderId)

推荐阅读