应直查系统表而非information_schema:PostgreSQL需联pg_attribute、pg_type、pg_enum等获取扩展类型详情;MySQL需混用COLUMNS、CHECK_CONSTRAINTS等视图提取生成列表达式与JSON校验;SQL Server应使用sys.types并关联assembly_types处理CLR UDT,且必须LEFT JOIN注释表确保字段不丢失。
导出 PostgreSQL 数据字典时,pg_type 和 pg_attribute 怎么连才不漏扩展类型?
postgresql 的 jsonb、citext、hstore、自定义 enum 或 domain 类型,不会直接出现在 information_schema.columns 的 data_type 字段里——它只返回 jsonb 这种“表面名”,但你真正需要的是“这个 jsonb 是不是带了自定义校验?”或“这个 enum 是哪几个值?”。所以得绕开 information_schema,直查系统表。
关键点是:必须用 pg_type 关联 pg_attribute,再左连 pg_enum(查 enum 值)、pg_class(查复合类型/域的定义来源),否则 citext 会被当成 text,jsonb 的生成列约束、domain 的 NOT NULL 默认行为全丢。
-
pg_attribute.atttypid指向pg_type.oid,这是类型源头 - 对
pg_type.typtype = 'd'(domain)要额外查pg_type.typbasetype和pg_type.typtypmod - enum 类型必须加
LEFT JOIN pg_enum ON pg_enum.enumtypid = pg_type.oid,否则枚举值列表为空
SELECT
n.nspname AS schema_name,
c.relname AS table_name,
a.attname AS column_name,
COALESCE(t2.typname, t.typname) AS base_type,
CASE WHEN t.typtype = 'e' THEN 'enum'
WHEN t.typtype = 'd' THEN 'domain'
ELSE 'base' END AS type_kind
FROM pg_attribute a
JOIN pg_class c ON a.attrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_type t ON a.atttypid = t.oid
LEFT JOIN pg_type t2 ON t.typbasetype = t2.oid
WHERE a.attnum > 0 AND NOT a.attisdropped;
MySQL 8.0+ 导出含 JSON Schema 校验和生成列的字典,information_schema 为什么查不到 GENERATED ALWAYS AS 表达式?
MySQL 的 information_schema.COLUMNS 里 extra 字段只写 STORED 或 VIRTUAL,不存表达式本身;而 JSON Schema 校验规则(JSON_SCHEMA_VALID)压根不进这个视图。真要完整导出,必须混用多个系统表。
核心路径是:information_schema.COLUMNS + information_schema.CHECK_CONSTRAINTS(找 JSON 校验)+ information_schema.COLUMN_DEFAULTS(补默认值)+ 直查 mysql.innodb_table_stats(仅限统计信息,非必需)。
-
COLUMNS.generation_expression字段在 MySQL 8.0.19+ 才有,旧版本只能靠SHOW CREATE TABLE解析,不可靠 - JSON Schema 校验实际存在
CHECK_CONSTRAINTS.check_clause,但内容是转义后的字符串,需UNHEX()+CONVERT(... USING utf8mb4)才能读成可读 JSON - 别依赖
COLUMNS.column_default判断是否为 NULL:它对函数默认值(如CURRENT_TIMESTAMP)返回NULL,但语义上不是“无默认”
SQL Server 导出字典时,sys.types 和 sys.systypes 到底该用哪个?
用 sys.types。后者是 SQL Server 2000 兼容视图,字段少、不更新,比如不包含 datetime2、time、hierarchyid 等新类型,且 systypes.xtype 和 types.system_type_id 映射混乱,容易把 varchar 错认成 char。
更麻烦的是用户定义类型(UDT):如果用了 .NET assembly 注册的 UDT(如 geometry),sys.types.is_assembly_type 为 1,此时必须关联 sys.assembly_types 才能拿到 CLR 类名和 assembly 名,否则字典里就只剩个黑盒 geometry。
-
sys.columns.user_type_id必须 joinsys.types.user_type_id,不能只看system_type_id - 对
max长度(如varchar(max)),max_length = -1,需特殊处理为字符串'max',而非留空或填 -1 -
sys.types.is_user_defined为 1 时,检查sys.types.schema_id是否属于用户 schema,避免把sys下的内置 UDT 当作业务类型
导出结果里要不要保留 COMMENT ON COLUMN 或 MS_Description?
要,而且必须作为一级字段导出。注释不是装饰,它是唯一能承载业务含义的元数据——比如字段叫 status,注释写 “0=待审核, 1=已通过, 9=已驳回”,这比任何类型名都关键。
但各数据库存法不同:PostgreSQL 存在 pg_description,MySQL 8.0+ 在 information_schema.COLUMNS.column_comment,SQL Server 要查 sys.extended_properties 且 class = 1(列级)+ name = 'MS_Description'。漏掉这个 JOIN,等于字典砍掉一半。
- PostgreSQL 中
pg_description.objsubid = 0是表级注释,= 1,2,3...才是列序号,别错连 - SQL Server 的
extended_properties不保证每列都有,必须LEFT JOIN,否则没注释的列直接消失 - MySQL 的
column_comment会自动截断超长内容(>1024 字符),导出前最好先SELECT LENGTH(column_comment)排查
复杂点在于跨库统一字段命名和空值处理:有的库把空注释存为 NULL,有的存为空字符串,导出脚本里得统一归为 NULL 或显式标记 '(no comment)',不然下游解析时容易误判缺失。










