SQL GROUP BY查询表数据重复:收支对比查询结果异常求助
排查SQL查询重复数据的原因及解决办法
嘿,我帮你揪出这个问题的根源啦!你的查询里出现的“重复数据”其实是聚合值被错误重复计算,核心原因是多表JOIN时产生了笛卡尔积,咱们一步步说清楚:
为什么会出现重复计算?
你同时把Ticket和Invoice两张表关联到Event表,如果一个活动(Event)对应N张售票记录、M条发票记录,那么JOIN之后会生成N×M条临时数据行。举个例子:1个活动有3张票、2条发票,JOIN后就会有6条记录。
这时候用sum(Ticket.Price)会把每张票的价格重复算2次(对应发票的数量),sum(Invoice.NetTotal)会把每条发票金额重复算3次(对应票的数量),最终的总和完全失真,看起来就像是数据重复了。
解决办法:先聚合再关联,避免笛卡尔积
这里给你两种靠谱的解决方案,你可以根据自己的需求选:
方案1:子查询预聚合后再关联
先分别计算每个活动的总售票额和总开销,再和Event表关联,从根源避免笛卡尔积:
SELECT e.Name as "Event", CONCAT("£", ROUND(COALESCE(t.TotalSales, 0), 2)) as "Ticket Sales", COALESCE(i.TotalCosts, 0) as "Invoice Costs", CONCAT("£", ROUND(COALESCE(t.TotalSales, 0) - COALESCE(i.TotalCosts, 0), 2)) as "Total Loss" FROM Event e LEFT JOIN ( -- 先计算每个活动的总售票额 SELECT EventID, SUM(Price) as TotalSales FROM Ticket GROUP BY EventID ) t ON e.EventID = t.EventID LEFT JOIN ( -- 先计算每个活动的总发票开销 SELECT EventID, SUM(NetTotal) as TotalCosts FROM Invoice GROUP BY EventID ) i ON e.EventID = i.EventID GROUP BY e.EventID, e.Name, t.TotalSales, i.TotalCosts;
用LEFT JOIN是为了保证即使某个活动没有售票记录或者没有发票记录,也能正常显示(如果用INNER JOIN会直接过滤掉这些活动);COALESCE用来处理NULL值,避免出现计算结果为NULL的情况。
方案2:SELECT中直接用子查询计算聚合值
如果你的表数据量不大,也可以直接在SELECT语句里用子查询分别获取每个活动的售票额和开销,写法更简洁:
SELECT e.Name as "Event", CONCAT("£", ROUND(COALESCE((SELECT SUM(Price) FROM Ticket WHERE EventID = e.EventID), 0), 2)) as "Ticket Sales", COALESCE((SELECT SUM(NetTotal) FROM Invoice WHERE EventID = e.EventID), 0) as "Invoice Costs", CONCAT("£", ROUND( COALESCE((SELECT SUM(Price) FROM Ticket WHERE EventID = e.EventID), 0) - COALESCE((SELECT SUM(NetTotal) FROM Invoice WHERE EventID = e.EventID), 0), 2)) as "Total Loss" FROM Event e;
额外注意点
- 原来的查询里
GROUP BY Event.EventID但SELECT包含Event.Name,在开启ONLY_FULL_GROUP_BY模式的SQL环境(比如MySQL默认开启)下会报错,因为Name没有被聚合也不在GROUP BY列表里,所以最好把e.Name也加到GROUP BY中,或者确保EventID是Event表的主键(此时Name由EventID唯一确定)。 - 可以检查一下你的表数据,确保
EventID关联没有错误(比如有没有无效的EventID值导致错误关联)。
内容的提问来源于stack exchange,提问作者Dan Lincoln
相关产品推荐
相关产品推荐

