MySQL 8.0+ 默认导出跳过虚拟列和STORED生成列;需用--skip-generated-columns=FALSE保留DDL定义,但值仍不导出;导出计算结果须用SELECT显式查询配合mysql客户端;LOAD DATA导入时必须排除生成列。
MySQL 8.0+ 导出时 mysqldump 自动跳过虚拟列?
默认情况下,mysqldump 不会报错,但会静默忽略 stored 和 virtual 生成列(generated column),导出的 sql 里不包含这些列定义,更不会导出其值——哪怕你用 select * 查出来有数据。
这是因为 mysqldump 默认按表结构导出 DDL,而虚拟列本身不存物理数据,STORED 列虽持久化但 dump 工具仍按“非基础列”策略跳过。
- 加
--skip-generated-columns(默认就开启)→ 跳过生成列定义和值,最常见表现就是导出后建表缺字段 - 想保留生成逻辑,必须显式关闭:用
--skip-generated-columns=FALSE(注意是字符串FALSE,不是布尔值) - 仅该参数还不够:它只保证 DDL 中包含
GENERATED ALWAYS AS (...) STORED/VIRTUAL,但不会导出列的「计算结果值」——因为虚拟列本就不存值
想导出虚拟列的「计算结果」,得绕开 mysqldump
如果你真正想要的是“把当前查询出来的虚拟列值一并导出成 CSV/Excel”,那本质不是导表结构,而是导查询结果。此时 mysqldump 不适用,它不执行表达式求值后再导出。
- 用
SELECT显式列出所有字段,包括生成列名 →SELECT id, name, full_name FROM user(假设full_name是生成列) - 配合
mysql客户端的输出控制:mysql -e "SELECT ..." --batch --raw > output.csv -
--batch关闭表格格式,--raw避免转义特殊字符(如换行、制表符),适合后续用sed或 Python 清洗 - 注意:如果生成列依赖函数(如
JSON_EXTRACT),确保目标 MySQL 版本支持,否则导出时会报错ERROR 3158 (HY000)
LOAD DATA INFILE 导入含生成列的 CSV 会失败?
即使你成功导出了带生成列值的 CSV,再用 LOAD DATA INFILE 导入时,MySQL 会拒绝写入生成列——无论它是 VIRTUAL 还是 STORED,只要列定义是 GENERATED ALWAYS,就不能在 INSERT 或 LOAD 中显式提供值。
- 错误信息典型为:
ERROR 3105 (HY000): The value specified for generated column 'xxx' is not allowed - 解决办法只有两个:① 在
LOAD DATA的INTO TABLE子句中,**明确排除生成列名**;② 改用INSERT ... SELECT+ 子查询构造非生成列字段 - 例如 CSV 有 5 列,其中第 4 列是生成列,那就写:
LOAD DATA INFILE 'x.csv' INTO TABLE t (col1,col2,col3,@dummy,col5),用@dummy占位跳过 - 别指望
SET col4 = DEFAULT能绕过——生成列不接受DEFAULT,这个语法直接报错
PostgreSQL / SQLite 怎么办?没 GENERATED COLUMN?
PostgreSQL 直到 12 才支持 GENERATED ALWAYS AS,且仅限 STORED(即物化),导出行为和 MySQL 类似:pg_dump 默认导出定义,但不导出值;若想导出计算结果,仍得靠 COPY (SELECT ...)。
SQLite 从 3.31.0 开始支持生成列,但只允许 ALWAYS AS + STORED,且 .dump 命令**完全不识别生成列语法**,会导出成普通列,导致恢复时报错 near "AS": syntax error。
- SQLite 必须手动改 dump 文件:删掉
GENERATED ALWAYS AS (...) STORED,只留列名和类型 - 或者改用
SELECT+.mode csv+.output绕过结构导出 - 跨数据库迁移时,生成列是最容易漏掉兼容性检查的一环——DDL 看似一样,但导出工具实现千差万别

















