Navicat 15导入SQL Server时主键冲突必须用“更新”模式:在目标表映射中将操作改为Update并手动勾选主键为匹配条件;“跳过重复记录”选项对SQL Server完全无效,因其无INSERT IGNORE等效语法。
Navicat 15导入SQL Server时主键冲突必须用“更新”模式而非“跳过”
navicat 的「跳过重复记录」选项对 sql server **完全无效**——它只在 mysql/postgresql 的 insert ignore 或 on duplicate key update 语义下起作用。sql server 没有等效语法,navicat 15 导入向导里所谓“跳过”实际是忽略该选项,仍按普通 insert 执行,遇到主键重复(error 2627)直接报错中断。
真正可行的路径只有一条:在导入向导第 2 步「目标表映射」中,将操作模式从默认的 Insert 改为 Update,并确保主键字段被正确勾选为匹配条件。
- 必须手动点击主键列名右侧的「匹配」复选框(哪怕它看起来已高亮),否则 Navicat 不会生成 WHERE 条件,
Update会变成全表覆盖 - 如果目标表有多个唯一约束(如
email+phone联合唯一),Navicat 只支持单主键匹配,此时需提前在 SQL Server 中建好视图或临时表,把多约束逻辑收口到一个计算列 - SQL Server 的
UPDATE模式不支持INSERT ... SELECT语法,Navicat 底层会拆成逐行MERGE,大数据量时明显变慢,建议单次导入控制在 5 万行以内
为什么“忽略主键冲突”勾选项在 SQL Server 导入里是灰色的
这个选项(Continue after error / 忽略错误)在 Navicat 15 的 SQL Server 导入流程中默认禁用,因为 SQL Server 的错误处理机制和 MySQL 不同:SET XACT_ABORT OFF 下单条 INSERT 失败不会终止整个批处理,但 Navicat 未启用该模式——它用的是原生 JDBC 驱动的默认事务行为,一旦触发主键冲突,驱动抛出 SQLException,Navicat 就终止执行。
你看到的灰色状态不是 Bug,而是 Navicat 主动屏蔽了不可靠的开关。试图通过修改注册表或配置文件强行启用,会导致后续语句执行错位(比如把第二行数据插进第一行位置)。
- 不要尝试在「高级」页勾选
Continue on error—— 它对 SQL Server 导入无响应 - 也不要依赖
SET IDENTITY_INSERT ON来绕过主键冲突,那仅解决自增列插入问题,对已有主键值重复无效 - 若源数据主键来自其他系统(如 UUID),确认目标表主键字段类型是
uniqueidentifier,而非int,否则类型转换失败会被误判为主键冲突
SQL Server 导入前必须检查的三个 Schema 差异点
主键冲突常被误认为是数据问题,实则 70% 源于 SQL Server 两端 schema 不一致。Navicat 不做 DDL 校验,只管 INSERT,所以错在源头。
导出前在源库运行:SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'your_table';在目标库运行同样语句,逐项比对:
-
IS_NULLABLE不一致:源为NOT NULL,目标为NULL,插入空值时触发主键外的约束失败,但 Navicat 日志统一标为“主键冲突” - 主键字段名大小写敏感:SQL Server 默认不区分,但如果目标库启用了
COLLATE Latin1_General_CS_AS,ID和id就是两个字段,匹配失败后 Navicat 会用全表 INSERT 回退,导致重复 - 标识列(IDENTITY)状态不同:源表主键是
INT IDENTITY(1,1),目标表却是普通INT,Navicat 会尝试插入显式值,而目标列没开SET IDENTITY_INSERT ON,报错代码仍是 2627
大表导入时如何避免主键冲突引发的隐性丢数据
Navicat 15 对 SQL Server 的批量导入没有真正的“断点续传”,一旦中途因主键冲突中断,重试时会从头开始,且不提示哪些行已被成功插入。更危险的是:当使用 Update 模式时,如果某行主键存在但非主键字段值为空(如 name = NULL),SQL Server 允许更新,但 Navicat 日志不标记,你以为跳过了,其实把有效数据覆盖成了 NULL。
安全做法是分两步走:
- 先用
Insert模式 +Truncate target table before import清空再插,适用于测试环境或可接受短时数据不可用的场景 - 生产环境必须用
Update模式,但导入前在目标库手动执行:SELECT COUNT(*) FROM target_table t WHERE EXISTS (SELECT 1 FROM source_data s WHERE s.pk = t.pk),预估冲突比例;若超过 5%,说明源数据清洗不到位,别硬导 - 导入完成后立刻查:
SELECT * FROM target_table WHERE pk IN (SELECT pk FROM source_data) AND (col1 source_data.col1 OR col2 source_data.col2),确认更新是否真生效——Navicat 不校验字段值变更,只看主键是否存在











