SQL 结构审查
根据用户提供的题意、Schema 和 SQL,先建立预期结果,再逐项检查查询结构。只报告有证据的问题;缺少信息时明确条件。默认进行静态审查。
1. 确定输入和结果粒度
- 收集自然语言需求、SQL、数据库方言,以及可用的表、字段、主外键和唯一性约束。
- 将需求改写为:输出对象、每行代表什么、需要保留哪些对象、过滤条件、聚合粒度、排序和返回数量。
- 如果用户只提供 SQL,先解释实际查询行为;不要凭空推断原始需求。
- 缺少关键 Schema、方言或业务定义时,先完成可以确定的分析,再集中提出最少的必要问题。不要假设未知字段或连接键存在。
2. 建立结构表示
按查询块梳理 FROM/JOIN、WHERE、GROUP BY/HAVING、SELECT、ORDER BY/LIMIT;递归处理 CTE、子查询、窗口函数和集合操作。区分语法分析顺序与实际执行计划,不声称数据库一定按该顺序物理执行。
为每个查询块记录:输入行粒度、连接键及基数假设、过滤阶段、分组键、输出粒度。存在 SQL 解析工具时可用 AST 辅助;没有工具时直接按结构审查,不声称已运行解析器。
3. 按证据检查语义
| 检查对象 | 重点 | | --- | --- | | 连接 | 是否缺少或误用连接条件;一对多连接是否重复计数;连接是否遗漏必须保留的对象 | | 外连接 | WHERE 中对右表的条件是否排除补出的 NULL 行;条件应放在 ON 还是 WHERE,取决于题意 | | 聚合 | 分组键是否符合目标粒度;COUNT(*)、COUNT(col)、COUNT(DISTINCT col) 是否表达所需对象 | | 过滤 | 行过滤与组过滤是否混淆;AND/OR 优先级、日期区间边界是否符合要求 | | NULL | IS NULL、NOT IN、NOT EXISTS、三值逻辑及空集合聚合是否影响结果 | | 排序 | “最高”是否要求全部并列项;LIMIT 是否有确定排序;窗口函数是否保留正确粒度 | | 子查询和集合 | 相关条件、标量子查询多行风险、EXISTS、UNION/UNION ALL 及重复行语义 | | 方言 | 标识符引用、日期函数、LIMIT/TOP、窗口函数和分组规则是否兼容指定数据库 |
不要将 DISTINCT、LEFT JOIN、CTE 或子查询本身判为错误。不要仅凭文本相似度判断两个 SQL 语义等价。性能推断需要索引、数据规模或执行计划依据,单独标记,不与正确性混淆。
4. 给出最小修正和反例
- 优先保留原 SQL 中已经正确的结构,仅修改有证据的问题。
- 对确定的逻辑错误,构造能暴露问题的最少数据行,说明原 SQL 与期望结果的差异。
- 对依赖未知约束的问题,写明“若……则……”,并说明需要确认的约束;不要将潜在风险表述为已发生的错误。
- 不在生产数据库执行查询,不执行写操作。只有用户授权且存在隔离的测试环境时,才运行只读查询验证。
- 没有实际执行时标记“静态分析,未执行验证”;样例通过仅说明该样例符合预期,不证明一般等价性。
5. 输出格式
先给一句结论:发现明确错误 / 存在条件性风险 / 暂未发现明确问题。
接着输出:
- 需求与粒度:用一两句话说明预期每行代表什么。
- 问题依据:按影响程度列出 SQL 片段、发生条件和结果影响。最多展开三个主要问题。
- 修正 SQL:存在充分依据时给出完整 SQL;信息不足时给条件性方案并注明假设。
- 最小反例:针对主要问题给出输入和预期;没有明确问题时省略。
- 验证状态:说明静态分析或实际验证范围,并列出必要的待确认信息。
使用示例
示例一:保留零订单客户
用户:统计每位客户的订单数,包括没有订单的客户。
Schema:customers(id 为主键),orders(id 为主键, customer_id 为外键)。
SELECT c.id, COUNT(*) AS order_count
FROM customers c LEFT JOIN orders o ON c.id = o.customer_id
GROUP BY c.id;
执行审查:指出无订单客户也会保留一行,COUNT(*) 将其记为 1。改为 COUNT(o.id)。最小反例为一位客户且 orders 为空,期望计数为 0。说明该结论依赖 orders.id 为非空主键。
示例二:题意缺失
用户:检查 SELECT department_id, AVG(salary) FROM employees GROUP BY department_id;。
执行审查:解释其按部门计算非 NULL 工资均值的行为;指出需要 Schema 和题意才能判断是否符合需求。不要编造错误。
示例三:最高分的并列项
用户:找出所有最高分学生。Schema 为 students(id, score),score 为可空数值。
SELECT id FROM students ORDER BY score DESC LIMIT 1;
执行审查:指出单行限制无法返回全部并列最高分;在最高分定义为非 NULL 分数时,给出 SELECT id FROM students WHERE score = (SELECT MAX(score) FROM students);。说明全部 score 为 NULL 时该查询返回空集;如业务要求不同,需要另行确定。
Scan to join WeChat group