Text-to-SQL 如何区分表结构与业务规则知识,并适应表结构变更?
未标记
考查重点:Schema 结构与业务语义。Schema 描述字段、类型和关联,业务知识描述指标、过滤与计算口径;检索两类信息生成 SQL,结构变更使相关缓存失效,再校当前库的执行结果
本题目录
参考答案
核心回答
把知识分成结构事实和业务语义,再通过稳定标识与版本关联。表结构说明“数据怎样存”,业务规则说明“这次应该怎样算”。 生成时需要两者共同约束;数据库变更后更新受影响的元数据、索引、示例和缓存,并重新验证查询。
两类知识分别保存什么
结构知识包括数据源、表列名称、类型、主外键、关联关系和可用字段。业务知识包括指标公式、计算粒度、过滤条件、单位、时区、时间口径、同义词及生效时间。
例如 amount 是数值类型,只是结构事实;“净销售额等于已支付金额扣除符合条件的退款,并按支付日统计”属于业务规则。字段注释可以帮助理解,但不足以自动推导全部规则。相同字段也可能服务于多个指标,不能只按字段名相似就认定同一口径。
检索时先锁定用户有权访问的数据源,召回相关结构与指标定义,再补齐连接键、计算依赖和必要的取值说明。给模型的规则应标明适用范围和版本;出现相互矛盾的有效规则,应澄清或交给维护者确认。
结构变化怎样处理
从变更流程或周期同步中检测表列新增、删除、重命名、类型和关联变化,对比旧版本生成影响列表。利用字段与指标、示例、索引的依赖关系更新受影响内容,并使相关查询缓存和生成缓存失效。
重命名不能简单做字符串替换:要确认它确为同一业务含义;类型变化可能影响比较、聚合和精度,关联变化可能引起重复统计。没有可靠映射时暂停受影响能力,比让模型猜一个近似字段更稳妥。
业务口径变化也应版本化。历史时间段是否沿用旧口径,需由业务定义,不应因为今天规则更新就悄悄改变历史统计解释。
如何验证更新完成
生成和执行校验要使用相容的结构版本;发现执行时结构已经变化,应刷新必要上下文并有限重试,不能把未知列错误原样无限回喂模型。新 SQL 重新检查权限与资源约束。
回归受影响的指标、连接、示例和权限用例,比较预期结果;保留知识来源、变更时间和对应版本,便于说明同一个问题为何在不同日期得到不同结果。EXPLAIN 通过只能说明数据库可以处理相应结构,无法证明业务口径同步正确。
对应教程
《实战项目-电商问数/8-表与字段信息同步到元数据库》:第2、3.3—3.4节区分配置中的业务语义与查询到的字段类型、取值;本文继续展开版本变更及依赖失效。
《电商问数:SQL生成前的信息过滤与补全》:对应候选表字段、指标精筛,以及日期和数据库环境补全。
参考资料
- 国内:飞致云:数据源概览:采用字段、类型、注释与关联关系的管理,界定结构事实及变更范围。
- 国内:飞致云:术语配置:采用术语、解释和同义词的分离管理,界定业务语义。
- 国内:飞致云:智能问数常见问题:借鉴问数上下文同时包含结构、术语和示例的说明,解释结构变化为什么会影响多类检索内容。
- 国内:飞致云:SQL示例库:采用数据源绑定的
SQL示例,说明变更后应检查示例的结构与口径依赖。 - 国外:Yale University:Spider: A Large-Scale Human-Labeled Dataset:参考表结构、连接关系与自然语言查询的对应,说明结构泛化不能靠字段字符串替换。
- 国外:PostgreSQL:Row Security Policies (PostgreSQL 18):核对数据访问策略依赖执行对象的边界,说明变更后也应回归权限范围。
SQLBotPython
核心回答
SQLBot 将表字段元数据、人工维护的表关系、业务术语和 SQL 示例分开管理,生成时再组合成上下文。表字段说明有哪些可用对象、类型和注释,表关系提供连接依据;术语解释业务含义与同义表达,示例则提供“问题—查询写法”的参考。字段类型本身不能说明库存余额采用哪个快照时点、滞销天数按哪类出库计算,这类口径需要补进业务说明或示例。
适应结构变化时,先同步真实表字段,再检查人工关系、业务说明和示例是否仍引用正确对象。该版本的结构同步会更新元数据并触发表与数据源的向量更新,但这条同步链没有自动迁移业务术语、改写示例 SQL 或清理全部生成依赖的过程。
不同知识怎样进入 SQL 上下文
以平台管理的普通数据源问数为例,get_table_schema() 从启用的表与字段构造结构信息,列权限过滤也在构造前处理。选表后,表名、字段名、类型与注释被组织成 Schema 文本;已有人工配置的 table_relation 会补充相关表及连接字段。这里的表关系来自维护的关系图,不等于系统自动读取并验证了数据库中的外键约束。表字段范围、结构与表关系组装。
业务语义走独立匹配:filter_terminology_template() 根据未扩展的关键词或原问题匹配术语,带上当前数据源等适用范围,返回主词、同义词与解释;filter_training_template() 按问题匹配该数据源范围内的 SQL 示例。开启向量匹配时可补充语义候选,结果随后被格式化为上下文,并非修改数据库结构或训练模型。术语匹配入口、示例匹配入口、术语模板、示例模板。
sql_sys_question() 分别构造结构、术语和示例模板,init_messages() 将这些内容逐项加入生成 SQL 的消息。结构信息与业务解释因此可以同时约束查询,但前提是对应内容确实被匹配并加入;只维护一条术语,并不代表每次生成都会使用它。模板构造、消息注入。
结构同步更新了什么
同步逻辑按表名、字段名匹配记录:已有表更新数据库注释,已有字段更新类型、原始注释和顺序,新表新字段创建记录。已有的 custom_comment 不会因此被数据库注释覆盖,所以人工维护的业务说明可以保留,也需要在含义变化时另行检查。表与字段同步。
同步结束会提交表和数据源的向量更新任务,这些任务在线程池中运行。触发更新与更新完成需要区分;重新生成时应检查实际选表结果及注入的结构,确认使用的是更新后的内容。单表字段更新、后台向量更新。
字段重命名也不会自动识别为同一业务字段的迁移。旧名称可能仍出现在术语解释、示例查询和人工关系配置中,相关内容需要单独确认和修改。若要实现“字段变化后自动定位并停用受影响的规则、示例与缓存”,还需要额外维护依赖关系与失效机制,不能仅靠同步表结构完成。
怎样验证一次变更
例如业务库把库存数量字段从 stock_qty 改成 on_hand_qty,且业务含义不变:先同步字段,检查注入结构是否已使用新名称;再检查相关术语、示例及连接配置中是否残留旧引用。用同一批问数问题重新生成查询,对照参考 SQL 检查库存快照、出入库和日期口径,并核对查询结果与可访问范围。
这能分别确认结构刷新、知识匹配与业务结果。查询成功执行只说明表字段和语法可用,不能证明新字段承接了原来的业务含义,也不能证明示例中的统计口径仍然正确。
WrenAIPython / Rust
核心回答
WrenAI 把物理结构与业务语义通过逻辑模型连接起来:数据库表列说明数据存在哪里,MDL 语义模型说明对外使用什么名称、怎样关联和计算。 当前架构由 Python SDK/CLI 加载模型、组织查询并连接数据源,Rust 语义引擎基于 Apache DataFusion 参与规划,将模型引用展开为目标数据库可执行的 SQL。
表结构改变后,更新物理映射和受影响的字段、关系或度量定义,重新构建 manifest,再让查询调用方使用新版本。仅改数据库,或者只改一段业务说明,都不会自动完成这条更新链;编译和查询可执行也不等于业务口径正确。
YAML 中哪些是结构,哪些是业务规则
项目把模型、关系、视图和聚合定义保存为可审阅的 YAML 与 SQL 文件:
- 模型与字段:
metadata.yml声明逻辑字段、类型和主键等信息,ref_sql.sql将逻辑模型映射到物理表或查询。类型是结构事实,对外名称、描述和计算表达式则带有语义选择。 - 度量与维度: cube 的
measures定义聚合或计算,dimensions定义按什么字段分组。它们明确“怎样算、按什么粒度看”,并非从字段类型自动推导。 - 关系:
relationships.yml保存模型间的连接条件及join_type,让可复用关系进入规划,而不是每次让模型仅凭同名字段猜连接。
原仓库的示例很具体:逻辑模型 orders 通过 ref_sql.sql 读取 public.raw_orders,声明每行是一笔订单;order_metrics 以 orders 为 base_object,定义 SUM(amount) 和 COUNT(*),以 customer_id 为维度。orders_customer 则声明订单到客户的 MANY_TO_ONE 关系。这里金额如何聚合、按谁分组、使用哪个连接条件,都是明确维护的定义。见示例度量与维度。
cube 在这条链中是逻辑聚合定义:查询先转换为普通 SQL,再交给引擎执行,不意味着已经自动生成物化聚合表。类似地,声明 MANY_TO_ONE 也不证明客户键在实际数据中唯一。关系粒度或数据质量不符合声明时,仍可能重复加总。
定义怎样进入查询规划
加载器读取模型目录的 metadata.yml,合并同目录的 ref_sql.sql,并加载关系、视图与 cube。wren context build 默认先检查项目结构,再调用 build_json(),将定义转成引擎使用的命名形式并写入 target/mdl.json。它不是把原始 YAML 直接塞进提示词。见模型加载与构建入口。
查询时,WrenEngine.dry_plan() 解析对逻辑模型的引用,提取相关 manifest,借助语义引擎与改写器展开模型和视图,生成目标方言的 SQL;query() 再通过对应连接器执行。cube 查询也先由 cube_query_to_sql() 生成基于其 base_object 的查询,再走相同引擎链。
因此,业务定义不只作为自然语言提醒,还会参与实际计算与连接的规划。Rust 侧能够检查部分模型依赖,例如 cube 基对象是否存在、派生度量是否成环、层级是否引用已声明维度;但“退款是否应该扣除”“金额单位是否一致”仍需先由业务定义并用数据核对。
结构变化后怎样更新
如果物理字段从 amount 改为 gross_amount,而含义和单位不变,可以修改模型映射,例如用 gross_amount AS amount 继续暴露逻辑字段 amount。这样,下游已确认的度量可以继续引用逻辑字段。若新字段已经变成含税金额或统计范围改变,就不能只加别名维持表面兼容,还要修改度量、说明及相关查询。
更新过程需要区分三件事:
- 修改源定义。 检查物理映射、列类型、连接条件、指标公式和业务说明的影响范围。
- 重新构建与索引。 构建新的
target/mdl.json;使用语义检索时,按项目工作流更新相应 memory 索引,使 Agent 读取的模型说明与执行定义一致。 - 让调用方加载新定义。 直接创建的
WrenEngine保存传入的manifest_str,不会因为 YAML 改动自动热更新。当前LangChainSDK 的ProjectMDLSource则在加载时重读target/mdl.json,工具调用据此创建引擎,因此外部构建的新文件可在后续调用中被拾取。不能把“改文件”“构建完成”“调用已使用新版本”视为同一时刻。见SDK 的 manifest 读取。
验证时先看规划后的物理 SQL 是否使用新字段与预期关系,再用固定数据检查总额、分组、空值和多表连接结果。还应保留一个会发生一对多放大的样例,核对聚合粒度。物理映射保持兼容,可以降低结构变化对上层查询的影响;业务口径本身改变时,则需要明确版本和生效范围,不能由兼容映射替业务做决定。
参考资料
- 国内:飞致云:SQLBot 最佳实践:参考结构说明、人工关系和业务术语分别维护的方式,解释仅有数据库表列不足以确定计算与连接口径。
- 国内:阿里云 Quick BI:数据准备:采用字段描述、数据形态和业务定义需要分别准备的分析,说明物理类型与分析语义不能混同。
- 国内:阿里云 Quick BI:问数知识管理:依据业务定义、同义词和生效范围的分工,说明结构兼容不等于口径兼容,业务变化仍需明确适用范围。
- 国内:NineData:Text2SQL / Chat2SQL:参考生成结果要核对对象、枚举、关联与聚合的要求,组织变更后的结果验证。
- 国外:AWS 与 Cisco:Enterprise-grade natural language to SQL generation using LLMs:采用用稳定结构抽象复杂物理关系、同时补充领域规则的思路,解释逻辑模型与物理映射的分工。
- 国外:dbt Labs:Semantic models:参考实体、维度和聚合定义共同构成语义层的分工;WrenAI 的实际字段、加载和规划方式以固定源码为准。
相关面经
1 篇字节跳动
AI 应用工程师如果业务表结构变了、加了新表,怎么处理?
