# 如何定义虚拟表 xly 中的*虚拟表*是作为元数据声明的“表”,不是 DDL 创建的真实表。框架之所以知道它,是因为 `gdsconfigtbmaster` 和 `gdsconfigtbslave` 中的行描述了它的形状;实际数据存储在真实物理表中,但框架操作的*抽象*是元数据声明。 这不同于数据库**视图**,视图是 `CREATE VIEW` SQL 对象。两者都可以通过 `gdsconfigformmaster.sType = 'table'` 或 `'view'` 支撑表单。 ## 虚拟表用途 - 让 PM 声明“我需要这种形状的东西”,无需工程师执行 `CREATE TABLE`。 - 定义下游表单可以叠加使用的数据形状。 - 集中管理租户感知的列定义,使多个读取同一形状的表单共享默认值。 当前实时 DB 中,`gdsconfigtbmaster` 有 307 个虚拟表 master 行,`gdsconfigtbslave` 有 14,385 个虚拟列行。它们覆盖 lookup 表、分类树和可配置参数集。 ## 配方 ### 1. 虚拟表 master — `gdsconfigtbmaster` 每个虚拟表一行: | 列 | 值 | |---|---| | `sId` | 唯一虚拟表 ID | | `sName` | 虚拟表逻辑名 | | `sChinese` / `sEnglish` / `sBig5` | 显示名 | | `sBrandsId` / `sSubsidiaryId` | 租户作用域 | | `sTbName` | 底层物理表名(如果有支撑表) | | 其他配置列 | 描述存储和索引 | ### 2. 列 — `gdsconfigtbslave` 每列一行。每行携带列名、类型、默认值、显示标签、校验规则,以及它是否属于主键。 ## 未决:数据由什么支撑 当前实时 DB 中,307 个 `gdsconfigtbmaster` 行都有非空 `sTbName`,但其中 11 个名称在 `information_schema.tables` 中找不到当前对象。因此安全表述是:元数据期望存在底层 SQL 对象,但实时 schema 并非对每个虚拟表行都完全对齐。 ## 何时选择虚拟表、视图或真实表 | 需求 | 选择 | |---|---| | PM 声明的新形状,并由真实(可能已有)表支撑 | 虚拟表 | | 跨已有表的只读 join | 数据库视图 | | 真正需要新存储且没有现有表可用的新形状 | 真实 `CREATE TABLE`(工程任务) | 虚拟表通道是框架对数据驱动形状的“类型系统”;物理 schema 才是真正存储行的地方。两者有意解耦。 ## 示例 本页需要一个具体示例:从 `gdsconfigtbmaster` 选一张真实虚拟表,逐行解释它的 master 行和 slave 行。后续版本应补上。