多次LEFT JOIN后按b.id和c.id分组统计B、C表行数的方法
解决方案
要避免直接关联后因笛卡尔积导致的统计错误,建议先对B、C表分别按ID预聚合统计行数,再与A表关联,最后按b.id和c.id分组(注:若某ID在B/C中无匹配,对应字段会返回NULL):
SELECT COALESCE(b.id, '无B表匹配') AS B_ID, COALESCE(c.id, '无C表匹配') AS C_ID, SUM(b.b_cnt) AS B_CNT, SUM(c.c_cnt) AS C_CNT FROM A LEFT JOIN ( SELECT id, COUNT(*) AS b_cnt FROM B GROUP BY id ) b ON A.id = b.id LEFT JOIN ( SELECT id, COUNT(*) AS c_cnt FROM C GROUP BY id ) c ON A.id = c.id GROUP BY b.id, c.id;
关键说明
- 子查询先对B、C表按ID统计行数,彻底避免了直接JOIN后产生的笛卡尔积导致重复计数的问题,这是效率最高的方案。
COALESCE函数用于将NULL值替换为易读文本,若不需要可以直接保留NULL,根据业务需求调整即可。
备选方案(仅适用于特定场景)
如果你的业务逻辑允许忽略笛卡尔积影响,或仅需统计存在关联的记录数,也可以用COUNT(DISTINCT)修正计数,但这种方式效率低于预聚合:
SELECT b.id AS B_ID, c.id AS C_ID, COUNT(DISTINCT b.唯一标识字段) AS B_CNT, -- 建议用B表的主键而非id,避免同id多重复记录的统计误差 COUNT(DISTINCT c.唯一标识字段) AS C_CNT FROM A LEFT JOIN B ON A.id = B.id LEFT JOIN C ON A.id = C.id GROUP BY b.id, c.id;
注意:如果B/C表中同一id对应多条记录,直接用COUNT(*)会因笛卡尔积导致结果偏大,必须用COUNT(DISTINCT 主键)或预聚合的方式修正。
内容的提问来源于stack exchange,提问作者SH Kwon
相关产品推荐
相关产品推荐

