让AI写SQL可以节省起草时间,但不能把生成的查询直接复制到生产数据库。SQL语句可能语法正确,却因为连接键不唯一、NULL处理不当、过滤条件位置错误或聚合口径不一致而返回错误结果。最危险的情况不是报错,而是结果看起来合理、数字也很漂亮,却悄悄改变了业务结论。下面是一套适合日常分析的七步验算流程。
一、先把业务问题改写成明确的口径
在看SQL之前,先写清楚统计对象、时间范围、去重规则、分母和排除条件。例如,“本月新增客户”是按注册日期、首次付费日期,还是第一次进入CRM的日期?同一个客户有多条订单时,是统计订单数还是客户数?如果口径不明确,AI无法替你决定哪一种才符合业务。
把问题拆成输入表、连接关系、筛选条件、聚合方式和输出字段。要求AI解释每个JOIN为什么需要、每个WHERE条件排除了什么,并列出它做出的假设。对方解释得通,不代表结果一定正确,但能让后续检查有抓手。
二、检查JOIN键是否唯一
一对多连接会让行数增加。例如客户表每个客户一行,订单表每个客户多行,连接后客户字段会重复出现。如果之后直接SUM客户级金额或COUNT客户记录,结果可能被放大。运行前先检查连接键的重复数量,比较连接前后的行数,并确认增加的行数是否符合业务关系。
如果只想判断是否存在关联记录,可以考虑EXISTS而不是把明细表直接JOIN进来。若需要先汇总订单再连接,就应明确汇总粒度。不要仅因为查询能执行,就假设JOIN后的每一行仍然代表原来的业务实体。
三、专门检查NULL与缺失值
SQL中的NULL不等于零,也不等于空字符串。使用等号判断NULL通常不能得到预期结果,应使用IS NULL或IS NOT NULL。聚合函数对NULL的处理也不完全相同;COUNT(*)统计行数,而COUNT(字段)通常只统计该字段非NULL的行。
检查AI是否把缺失值直接替换成0,是否把没有匹配记录的客户误认为消费为零,以及LEFT JOIN之后把右表字段写进WHERE是否意外过滤掉没有匹配项的行。最好用三五条手工构造的样例验证边界情况。
四、核对WHERE、HAVING和时间边界
WHERE通常在分组前筛选行,HAVING用于筛选分组结果。AI如果把条件放错位置,查询可能报错,也可能得到看似合理但含义不同的结果。时间条件尤其容易出错:本月、过去30天、自然日和滚动24小时不是同一个口径。
明确时区、开始时间是否包含、结束时间是否包含,并检查跨月、跨年和夏令时场景。对于“截至今天”的报告,要确认今天是否只统计到当前时刻,还是统计完整自然日。
五、先用只读方式验证结果
先查看执行计划、估算扫描范围和结果样例,再在只读副本或受限账号下运行。不要让AI生成的脚本直接执行UPDATE、DELETE或DDL。若确实需要写操作,应先由人审核影响范围,使用事务、备份和明确的回滚方案。
OWASP建议使用参数化查询处理外部输入,避免把数据拼接成SQL语法。对AI生成的SQL也适用:用户输入、筛选条件和变量应该作为参数传递,而不是拼接进查询字符串。权限也要最小化,报表账号不应拥有不必要的写权限。
六、用独立方法交叉核对
选取几个已知样例,手算预期结果,再与SQL输出比较。也可以先用较简单的查询分别统计表A、表B和连接后的行数,逐步增加JOIN与聚合。对财务、订单或客户指标,抽查原始记录比单纯比较两个SQL结果更有价值。
如果旧报表有可靠基线,比较新旧结果的差异,并要求AI解释差异来源。差异不是自动意味着新查询错误,但每一项明显变化都应该能追溯到口径或数据变化。
七、把检查清单保存为团队规范
最终验收应包含业务口径、表粒度、JOIN键、NULL处理、时间范围、行数变化、聚合结果、只读权限和抽样核对。将发现过的错误加入回归样例,下次模型或提示词更新后重复测试。这样,团队不会每次都从零开始,也能逐步知道AI在哪些SQL任务上可靠、在哪些任务上需要更强的人工复核。
OWASP的SQL注入防护指南和Microsoft SQL文档可作为查询编写与输入处理的基础参考。AI可以加快起草,但业务口径和结果正确性仍需可复核的测试来保证。
Sources
- OWASP:SQL Injection Prevention Cheat Sheet(访问于2026年10月28日)。
- Microsoft Learn:SELECT(Transact-SQL)(访问于2026年10月28日)。