navicat 同步 sql server 时间戳字段失败的根本原因是将 getdate() 等函数默认值误作文本处理且不校验大小写与括号,导致空值写入非空时间字段而报错或填入1900-01-01;须手动在字段映射中设置 isnull(?, getdate()) 并预先在目标库配置默认约束或触发器。

Navicat 同步 SQL Server 时间戳字段失败,根本原因不是字段类型不兼容,而是它把 GETDATE() 这类函数默认值当作文本处理,且不校验大小写与括号完整性——同步时若目标列没显式设默认值或触发器,空值直接写入,而 SQL Server 会拒绝插入 NULL 到非空时间字段。
SQL Server 时间字段同步失败的典型现象
常见错误包括:
-
Cannot insert the value NULL into column 'created_at'—— 源数据某行该字段为空,但目标列定义为NOT NULL且无默认值 - 同步后所有时间字段都变成
1900-01-01 00:00:00.000—— Navicat 把空值转成最小 datetime,而非调用GETDATE() - 同步日志里显示“1 warning”,但没报错,结果数据明显异常 —— 实际是
STRICT_TRANS_TABLES类似机制在起作用(SQL Server 的 ANSI_WARNINGS 或 ARITHABORT 设置影响)
必须手动补全 GETDATE() 并禁用自动推断
Navicat 在读取源表结构时能识别 GETDATE(),但不会自动把它带进 INSERT 语句;它默认用空值或字符串占位。你得主动干预:
- 在 Navicat 数据同步向导的「高级」页中,取消勾选
Auto-detect default values(如果存在该选项;部分版本叫Use source default values) - 对每个时间字段,在「字段映射」里点击「编辑」→「转换表达式」栏填:
ISNULL(?, GETDATE())(?是源字段占位符) - 若目标列允许 NULL,但你想统一补当前时间,改用:
CASE WHEN ? IS NULL THEN GETDATE() ELSE ? END - 别依赖 Navicat 自动生成的 DDL:它导出的脚本常把
GETDATE()写成getdate(),迁移到 Linux 版 SQL Server 时会报Invalid column name 'getdate'
目标表必须提前建好并设好默认值或触发器
Navicat 的 Data Transfer 不支持跨异构数据库自动创建带函数默认值的列。如果目标表是空的,或由 Navicat 自动建表,DEFAULT GETDATE() 很可能被丢弃或写错:
- 务必先在目标 SQL Server 上用 SSMS 执行:
ALTER TABLE [table] ADD CONSTRAINT DF_table_created_at DEFAULT GETDATE() FOR [created_at]; - 若需更新时间(如
updated_at),不能只靠 DEFAULT —— 必须加AFTER UPDATE触发器,或改用datetime2+ON UPDATE CURRENT_TIMESTAMP(仅 SQL Server 2016+ 支持) - 检查目标列是否为
NOT NULL:如果源数据含 NULL,而目标列又没默认值,同步必然中断
最容易被忽略的是:Navicat 从不验证你写的 GETDATE() 是否真被 SQL Server 执行了。哪怕同步界面显示“成功”,只要没在目标库查 SELECT TOP 1 created_at FROM table 确认值是当前时间,就可能还在用 1900 年那个兜底值。











