根本原因是目标表AUTO_INCREMENT值小于已存数据最大id;应先查MAX(id),再设ALTER TABLE ... AUTO_INCREMENT = MAX(id)+1(仅InnoDB可靠)。

MySQL 导入时主键冲突:AUTO_INCREMENT 没对齐
直接原因不是数据重复,而是目标表的 AUTO_INCREMENT 值小于已存数据最大 id。比如导出 SQL 里含 INSERT INTO t VALUES (1001, ...),而目标表当前 AUTO_INCREMENT = 1000,下一条就撞上 1001,报 ERROR 1062。
解决思路分两步:先查真实最大值,再设对齐值。
-
SELECT MAX(id) FROM tbl_name;—— 必须执行,不能靠估算 -
ALTER TABLE tbl_name AUTO_INCREMENT = N;——N至少为MAX(id) + 1,且仅对InnoDB表可靠 - 线上大表慎用
ALTER TABLE,会锁表;可改用TRUNCATE ... RESTART IDENTITY(仅限清空场景)
PostgreSQL 序列与主键不一致怎么修
PG 的自增本质是序列(serial 或 GENERATED BY DEFAULT AS IDENTITY),主键值和序列值脱节是常见根源。例如手动插入过 id = 5000,但序列还停在 100,下次 INSERT 就会冲突。
关键操作是把序列值拉到和当前最大主键对齐:
- 查序列名:
SELECT pg_get_serial_sequence('tbl_name', 'id'); - 重置序列:
SELECT setval('tbl_name_id_seq', (SELECT MAX(id) FROM tbl_name)); - 注意:
setval(..., false)表示“下次NEXTVAL返回该值”,true才表示“跳过该值”
SQL Server 重置自增列:DBCC CHECKIDENT 的坑
DBCC CHECKIDENT 是最常用方式,但它不校验已有数据是否超出新种子值。比如执行 DBCC CHECKIDENT ('t', reseed, 1) 后插入,若表里已有 id = 5,仍会触发唯一键冲突。
安全做法必须加验证:
- 先查最大值:
SELECT ISNULL(MAX(id), 0) FROM t; - 再重置:
DBCC CHECKIDENT ('t', reseed, @max_id + 1); -
TRUNCATE TABLE t可一键清空并重置,但不可回滚、会丢权限定义,别在有外键依赖时直接用
INSERT IGNORE 和 ON DUPLICATE KEY UPDATE 不是万能解药
它们能绕过冲突继续执行,但掩盖了底层不一致问题。比如你用 INSERT IGNORE 导入一批数据,部分因主键重复被静默跳过,你以为成功了,其实漏了记录。
适用场景很窄:
- 明确接受“跳过重复”语义,如日志去重、缓存写入
- 导入脚本可控(比如程序拼 SQL),能加
ON CONFLICT DO NOTHING(PG)或INSERT ... SELECT做条件过滤 - 绝不能替代
AUTO_INCREMENT或序列对齐——那是治标不治本
真正容易被忽略的是:不同数据库对“重置”的定义完全不同。MySQL 的 AUTO_INCREMENT 是表级元数据,PG 的序列是独立对象,SQL Server 的标识列种子绑定在表结构里。修错地方,等于没修。

















