insert ignore仅mysql支持,专用于静默跳过主键或唯一索引冲突(error 1062),其他错误仍报错;sql server需用merge,postgresql用on conflict实现更精细控制。

INSERT IGNORE 只在 MySQL 中有效,且仅跳过主键或唯一索引冲突;SQL Server 和 PostgreSQL 完全不支持该语法,强行套用会报错或静默失效。
MySQL 用 INSERT IGNORE 跳过重复,但别信“跳过”字面意思
它不是容错开关,而是冲突过滤器:
- 只对
ERROR 1062(主键/唯一索引重复)静默跳过,其他错误如ERROR 1366(字符集不匹配)、ERROR 1265(字段截断)、NOT NULL插NULL仍会报错 -
mysql_affected_rows()返回0表示“被忽略”,不是失败——很多代码误判为执行异常 - 多个唯一索引(比如
email和phone都设了UNIQUE),只要其中任一冲突,整行就被丢弃,不会部分插入 -
INSERT IGNORE INTO users (id, email) VALUES (1, 'a@b.com');若id=1已存在,语句成功返回,但查不到新数据——这是预期行为,不是 bug
SQL Server 没有 INSERT IGNORE,必须用 MERGE 或 Navicat 的 Update 模式
Navicat 15 导入时勾选“跳过重复记录”对 SQL Server 完全无效,那个选项是灰色的,不是 UI Bug,是驱动层根本没实现:
- 真实可行路径只有:在导入向导第 2 步「目标表映射」中,把操作从
Insert改成Update,并手动勾选主键列为「匹配」条件 - 若目标表有联合唯一约束(如
(email, tenant_id)),Navicat 不支持多列匹配,得提前建视图或用MERGE语句手写 - 原生写法推荐
MERGE:它明确区分WHEN MATCHED THEN UPDATE和WHEN NOT MATCHED THEN INSERT,语义清晰,且能控制是否更新时间戳等字段 - 避免用
SET IDENTITY_INSERT ON试图绕过主键冲突——它只解决自增列插入限制,对已有主键值重复无用
PostgreSQL 用 ON CONFLICT,比 MySQL 更精细、更安全
它的设计就是为替代 INSERT IGNORE 和 REPLACE 这类模糊语义:
-
INSERT INTO users (id, email) VALUES (1, 'a@b.com') ON CONFLICT (id) DO NOTHING;—— 精准指定按哪个约束跳过 - 支持复合唯一索引:
ON CONFLICT (email, tenant_id) DO NOTHING - 还能做有条件忽略:
ON CONFLICT (id) WHERE status = 'active' DO UPDATE SET updated_at = NOW() - 不触发序列跳号(
serial或IDENTITY列不会因冲突而浪费值),这点比 MySQL 的ON DUPLICATE KEY UPDATE更稳
真正难的不是语法,而是确认“谁才算重复”
空字符串 '' 和 NULL 在唯一索引里是否算冲突?不同数据库行为不一致:
- MySQL:多个
NULL不视为重复(UNIQUE索引允许任意多NULL),INSERT IGNORE会继续插入,可能造成逻辑重复 - PostgreSQL:标准
UNIQUE约束中,NULL = NULL为 false,所以多个NULL不冲突;但加了IS NOT DISTINCT FROM的表达式索引可改变此行为 - SQL Server:
UNIQUE约束默认允许多个NULL,和 MySQL 一致
上线前务必用真实数据验证 NULL / 空字符串 / 大小写敏感字段的冲突表现——这些细节往往在测试库里跑不出问题,一上生产就暴露。










