三表INNER JOIN查询重复数据:John薪资与收款求和结果异常
解决三表连接导致聚合结果偏大的问题
这个问题我经常碰到——当你直接关联多个存在一对多关系的表时,笛卡尔积会让聚合计算重复统计数据,最终结果自然就偏大了。
问题原因分析
你当前的SQL直接把Customers和Salary、Receipts做内连接,假设John(Id=1)在Salary中有1条记录、Receipts中有1条记录,连接后是1条数据,结果没问题;但如果John在Salary中有多条记录,Receipts中也有多条记录,连接后会生成「薪资记录数×收款记录数」条数据,每条薪资会被重复统计N次(N是收款记录数),每条收款会被重复统计M次(M是薪资记录数),SUM出来的数值就会是实际值的数倍。
正确的解决方案
先分别对Salary和Receipts按客户ID聚合求和,得到每个客户的总薪资和总收款,再和Customers表关联,这样就彻底避免了笛卡尔积的问题。
具体SQL代码如下:
SELECT cus.Name, COALESCE(sal.TotalSalary, 0) AS Salary, COALESCE(re.TotalReceipts, 0) AS Received FROM Customers cus LEFT JOIN ( -- 先计算每个客户的薪资总和 SELECT Id, SUM(Amount) AS TotalSalary FROM Salary GROUP BY Id ) sal ON cus.Id = sal.Id LEFT JOIN ( -- 再计算每个客户的收款总和 SELECT Id, SUM(Amount) AS TotalReceipts FROM Receipts GROUP BY Id ) re ON cus.Id = re.Id WHERE cus.Id = 1;
代码说明
- 子查询聚合:两个子查询分别对
Salary和Receipts按Id(关联Customers的字段)分组求和,确保每个客户在子查询中只有一条汇总记录。 - LEFT JOIN + COALESCE:使用
LEFT JOIN可以兼容客户没有薪资或收款记录的情况,COALESCE把NULL值替换为0,结果更符合业务预期。 - 精准过滤:最后通过
WHERE cus.Id=1筛选John的数据,得到准确的总和。
用你提供的测试数据执行这段SQL,会得到正确结果:
| Name | Salary | Received |
|---|---|---|
| john | 300 | 500 |
内容的提问来源于stack exchange,提问作者khorshid
相关产品推荐
相关产品推荐

