执行INSERT SELECT报Duplicate entry OpenOrder.PRIMARY错误排查
问题原因
你遇到的主键冲突错误本质是去重判断逻辑和表实际的唯一约束规则不匹配,具体有两个常见触发场景:
- 你当前判断记录重复的依据是
symbol、clientorderid、orderid、price四个业务字段联合相等,但OpenOrder表的主键是独立的数值型单字段(从报错Duplicate entry '2'可判断),你写的SELECT OpenOrderTemp.*会把Temp表的主键id字段也查出来插入:如果OpenOrder里已经存在id=2的记录(哪怕这条记录的四个业务字段和Temp表里id=2的记录完全不匹配),左连接会因为业务字段不匹配判定为"待插入新记录",实际插入时就会触发主键重复冲突。 - OpenOrderTemp表内部本身存在重复主键/重复唯一键的记录:哪怕这些记录在OpenOrder里都不存在,同批次插入时也会因为Temp表内部的重复键触发报错。
另外你写SQL时给右表OpenOrder起的别名和原表名完全一致,很容易出现字段引用歧义,属于不规范写法。
修复方案
- 禁止使用
SELECT *做插入查询,明确指定需要插入的字段:如果主键是自增属性,不要从Temp表携带主键id值,交给数据库自动生成即可,从根源避免主键值冲突。 - 调整表别名,避免别名和原表重名导致的字段引用错误。
- 对Temp表的待插入数据先做去重,避免同批次插入重复数据。
- (可选)如果业务规则确定四个业务字段联合唯一,直接给OpenOrder表加四个字段的联合唯一索引,后续可以用更高效的
INSERT ... ON DUPLICATE KEY UPDATE或者INSERT IGNORE语法实现不存在则插入的逻辑,稳定性比左连接判空更高。
修正后的SQL参考:
-- 注意:括号里的字段列表要和SELECT里的字段一一对应,按你表的实际字段补全即可 INSERT INTO OpenOrder (symbol, orderid, clientorderid, price, 其他业务字段按顺序列) SELECT DISTINCT t.symbol, t.orderid, t.clientorderid, t.price, t.对应其他业务字段 FROM OpenOrderTemp t LEFT JOIN OpenOrder o ON o.symbol = t.symbol AND o.clientorderid = t.clientorderid AND o.orderid = t.orderid AND o.price = t.price WHERE o.symbol IS NULL;
排查验证语句
可以先执行以下两个查询定位具体冲突来源:
- 查询Temp表中主键id已经在OpenOrder表存在的记录
SELECT t.id, COUNT(*) AS conflict_num FROM OpenOrderTemp t INNER JOIN OpenOrder o ON t.id = o.id GROUP BY t.id;
- 查询Temp表内部自身存在重复主键的记录
SELECT id, COUNT(*) AS duplicate_num FROM OpenOrderTemp GROUP BY id HAVING COUNT(*) > 1;
内容的提问来源于stack exchange,提问作者antonioleng
相关产品推荐
相关产品推荐

