先问一行代表什么,再看SUM
让Claude修改统计SQL时,结果看起来合理却比手工账单大,常见原因是连接后的一行不再代表一张订单。先写明统计对象和包含条件,再检查连接关系;不是见到重复就加DISTINCT。
本文练习的需求很窄:只统计至少有一条明细的订单金额,每张订单算一次。订单金额以整数单位记录,样例只存在内存中,不连接任何业务库。
三张订单足以复现两个错误
虚构订单A金额100,有明细x、y;B金额100,有明细z;C金额80,没有明细。符合“至少一条明细”的只有A与B,人工期望合计200。若改为所有订单,答案才是280。
把orders与items按订单号直接JOIN后,A出现两行、B一行。SUM(o.amount)得到300,放大的不是金额字段,而是参与求和的行数。

为什么SUM DISTINCT仍然不对
将表达式改成SUM(DISTINCT o.amount),本例只剩一个不同金额100,结果变成100。A与B是两张不同订单,恰好金额相同;按金额去重把本该保留的B也丢了。
正确的唯一性应来自订单标识,而不是金额或客户名称。给Claude追问时,应要求它列出连接后每一行和订单ID,不只输出修改后的SQL与一句“已去重”。
用EXISTS表达本例真实需求
本例只需要判断订单有没有明细,不需要从明细取字段。EXISTS子查询返回存在性,外层仍一行一订单,因此求和得到200。文末代码同时保留错误JOIN、错误DISTINCT、正确EXISTS和所有订单总和,方便对照。
若真实需求还要按商品、退款或日期拆分,EXISTS不一定就足够。先定义金额属于订单还是明细,必要时让明细先按订单聚合再连接,并明确没有明细时是否保留。不能把本文修复机械套入所有报表。
怎样运行和验收
将完整代码存为sql-join-grain.mjs,用Node.js 24 LTS运行:node sql-join-grain.mjs --demo。应得到bad为300、distinctWrong为100、correct为200、allOrders为280。Node可能显示内置SQLite实验性提示,不影响本例只读内存结果的解释。
请Claude解释四个数分别来自哪些行,再增加金额相同的第二订单、零明细订单两类回归样例。若只用每张订单金额都不同的样例,错误DISTINCT可能暂时蒙混过关。
把数据库方言和验证范围写进交接
代码已在本地Node.js 24的SQLite实际执行,并核对这四个数;没有用Claude真实生成查询,也没有在MySQL、PostgreSQL或线上数据中测试。换数据库时需核对语法、空值和执行计划。
正式替换查询前,在授权测试数据上比较逐订单明细与总数,保留旧查询及解释。不要为了得到期望总数删掉看似重复的真实订单。
参考资料与核验范围
资料核对日期:2026年10月20日。以下为官方原始资料;产品入口和可用范围仍以当前账户为准。
1. [官方资料1](https://platform.claude.com/docs/en/test-and-evaluate/develop-tests)
2. [官方资料2](https://www.sqlite.org/lang_select.html)