sql-server - 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 行。所以在我的情况下,它在性能方面有很大的不同。
解决方案
有两条@source
相同的记录OrderID
。中的任何一条记录都不匹配,@target
因此该NOT MATCHED
子句试图插入这两条记录。但它不能这样做,因为表OrderID
中的主键@target
要求所有插入的记录都具有唯一的值OrderID
。将值复制到主键中会导致主键违规。
如果您期望源中可能出现重复...您应该在USING
子查询中消除它们。像这样的东西:
(SELECT orderId, max(customerId) customerId
FROM @source
group by orderId)
推荐阅读
- vue.js - Vue JS 组件结构
- ios - UIButton 高度和自动布局
- java - Simpledateformat 解析字符串日期错误
- asp.net-mvc - Asp.net 核心 - 通过 Ajax 调用填充下拉列表
- python - 为什么 CreateView 不将参数传递给表单集?
- c# - HttpContext:在服务器上运行时用户身份为空
- swift - 如何修复 4 个水平标签的约束?
- spring-security - 无法在 Spring Boot 实现的授权服务器中获取身份验证对象
- python - 如何键入提示变量应该是另一个类的变量?
- android - 阿联酋 (AED) 货币的 Paypal 支付网关集成