navicat 15 不支持解析 generated always as,同步时跳过虚拟列定义,导致字段类型错误、索引失效或建表失败;必须手动通过 show create table 获取完整 ddl 并注入虚拟列语句,且需确认目标库 mysql 版本 ≥ 5.7。
navicat 15 对 generated always as 不支持解析
navicat 15(含 premium 15)在反向工程或结构同步时,会跳过 generated always as 子句,导致目标表缺失虚拟列定义,甚至建表失败。它把这类列当成普通列处理,不识别其表达式、存储属性和依赖关系——结果就是同步后字段类型错(比如变成 varchar(255))、默认值为空、索引失效,或直接报 error 1901 (hy000): function or expression 'xxx' cannot be used in the generated always as clause。
- Navicat 不解析
SHOW CREATE TABLE输出中的AS (expr) STORED/VIRTUAL部分,只提取基础列名和类型 - 若源表用 MySQL 8.0.23+ 的函数索引(如
INDEX idx ON t ((UPPER(name)))),Navicat 会完全忽略该索引,同步脚本里不生成 - 当虚拟列被用作外键、主键或唯一约束的一部分时,Navicat 可能报
ERROR 3750 (HY000): Unable to create foreign key constraint,因为它没同步列定义,却试图建约束
同步前必须手动补全虚拟列 DDL
不能依赖 Navicat 自动生成的 SQL。你得从源库导出真实结构,再人工注入虚拟列定义。
- 在源库执行:
SHOW CREATE TABLE `table_name`;,复制整段 DDL - 在 Navicat 同步向导的「选项」页中,**取消勾选**
Drop objects not exist in source和Recreate tables——否则它可能先删表,再用残缺 DDL 重建,彻底丢掉虚拟列 - 改用「仅同步差异对象」模式,在预览阶段点击「保存为 SQL 文件」,然后打开该文件,在
CREATE TABLE语句里手动插入缺失的col_name VARCHAR(50) GENERATED ALWAYS AS (...) VIRTUAL行 - 注意:MySQL 5.7 不支持虚拟列,若目标库是 5.7,同步必然失败;需提前确认版本兼容性
虚拟列依赖函数或 JSON 表达式时更易出错
Navicat 对复杂表达式几乎无容错能力。哪怕只是 AS (JSON_EXTRACT(data, '$.name')),它也可能把整个列解析成 TEXT 并丢掉表达式,后续同步到目标库时报语法错误。
- 检查源表是否用了非确定性函数(如
NOW(),RAND())——MySQL 不允许在虚拟列中使用它们,但 Navicat 不校验,同步后目标库建表直接失败 - 若表达式含反引号或双引号(如
AS (`a` + `b`)),Navicat 生成的 SQL 常漏转义,导致目标库报ERROR 1064 - 安全做法:在源库用
SELECT column_name, generation_expression FROM information_schema.columns WHERE table_name = 't' AND extra LIKE '%VIRTUAL%';单独查出所有虚拟列表达式,逐个核对是否可被目标库接受
替代方案:绕过 Navicat,用原生命令同步
对含虚拟列的表,最稳的方式不是调 Navicat 向导,而是用 mysqldump 导出结构,人工清理后再导入。
- 导出命令:
mysqldump --no-data --skip-triggers --routines --compact --set-gtid-purged=OFF db_name table_name > schema_virtual.sql - 打开
schema_virtual.sql,确认GENERATED ALWAYS AS完整存在;若无,说明源库 MySQL 版本太低( - 导入前,在目标库执行:
SET sql_mode = '';(避免 strict mode 拦截表达式) - 用
mysql -u user -p db_name 执行,比 Navicat 同步更可靠
真正麻烦的不是 Navicat 忽略虚拟列,而是它不报错、不警告,静默生成错误 DDL——等你发现数据不准或查询报错时,往往已同步多轮,回溯成本极高。











