MySQL使用INSERT INTO SELECT结合MAX+1插入时序列重复问题求解
问题原因
你原先的写法存在两个问题:
- 分组逻辑按
mid + itemcode聚合,同一个mid下的所有itemcode分组查询到的A表对应mid的最大seq完全一致,所以max(A.seq)+1的结果对同一个mid下的所有待插入行都相同,必然出现seq重复 - 内连接的写法会漏掉B表中存在但A表中不存在的mid(比如示例中的mid=3),这部分数据不会被插入
正确实现方案
方案1:支持窗口函数的数据库(MySQL 8.0+、PostgreSQL、SQL Server等)
优先使用窗口函数实现,逻辑清晰性能更好:
INSERT INTO A (mid, itemcode, seq) SELECT t.mid, t.itemcode, COALESCE(m.max_seq, 0) + ROW_NUMBER() OVER(PARTITION BY t.mid ORDER BY t.itemcode) AS seq FROM B t LEFT JOIN ( -- 预查询每个mid在A表中的最大seq值 SELECT mid, MAX(seq) AS max_seq FROM A GROUP BY mid ) m ON t.mid = m.mid;
按你的测试数据执行后,mid=1的两条待插入数据seq分别为4、5,mid=2的两条为3、4,mid=3的为1,完全符合同mid下seq连续递增的要求。
方案2:兼容不支持窗口函数的低版本数据库(如MySQL 5.x)
用关联子查询生成同mid下的行号:
INSERT INTO A (mid, itemcode, seq) SELECT t1.mid, t1.itemcode, COALESCE(m.max_seq, 0) + ( SELECT COUNT(*) FROM B t2 WHERE t2.mid = t1.mid AND t2.itemcode <= t1.itemcode ) AS seq FROM B t1 LEFT JOIN ( SELECT mid, MAX(seq) AS max_seq FROM A GROUP BY mid ) m ON t1.mid = m.mid;
如果需要按B表的原始插入顺序生成seq,可以将子查询的排序条件替换为B表的自增主键字段即可。
注意:如果你实际业务中的字段名是
memberid而非表结构里的mid,将上述语句中所有mid替换为memberid即可。
内容的提问来源于stack exchange,提问作者user1819769
相关产品推荐
相关产品推荐

