进阶设计指南之如何导出数据库完整数据字典_支持高级扩展类型

1次阅读

应直查系统表而非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_typepg_attribute 怎么连才不漏扩展类型?

postgresql 的 jsonbcitexthstore、自定义 enum 或 domain 类型,不会直接出现在 information_schema.columnsdata_type 字段里——它只返回 jsonb 这种“表面名”,但你真正需要的是“这个 jsonb 是不是带了自定义校验?”或“这个 enum 是哪几个值?”。所以得绕开 information_schema,直查系统表。

关键点是:必须用 pg_type 关联 pg_attribute,再左连 pg_enum(查 enum 值)、pg_class(查复合类型/域的定义来源),否则 citext 会被当成 textjsonb 的生成列约束、domainNOT NULL 默认行为全丢。

  • pg_attribute.atttypid 指向 pg_type.oid,这是类型源头
  • pg_type.typtype = 'd'(domain)要额外查 pg_type.typbasetypepg_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.COLUMNSextra 字段只写 STOREDVIRTUAL,不存表达式本身;而 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.typessys.systypes 到底该用哪个?

sys.types。后者是 SQL Server 2000 兼容视图,字段少、不更新,比如不包含 datetime2timehierarchyid 等新类型,且 systypes.xtypetypes.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 必须 join sys.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 COLUMNMS_Description

要,而且必须作为一级字段导出。注释不是装饰,它是唯一能承载业务含义的元数据——比如字段叫 status,注释写 “0=待审核, 1=已通过, 9=已驳回”,这比任何类型名都关键。

但各数据库存法不同:PostgreSQL 存在 pg_description,MySQL 8.0+ 在 information_schema.COLUMNS.column_comment,SQL Server 要查 sys.extended_propertiesclass = 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)',不然下游解析时容易误判缺失。

text=ZqhQzanResources