同一表多Join使用错误:多类型消息计数异常排查
问题分析与解决方案
嗨,这个问题我之前也踩过坑!咱们先拆解下问题出在哪儿,再给你几个实用的解决办法~
为什么两次LEFT JOIN会出错?
当你连续LEFT JOIN两次messages表(一次匹配request,一次匹配report),如果某个公司同时存在两种类型的消息,这两次关联会产生笛卡尔积。举个例子:
- company2有2条
request和1条report,关联后会生成2×1=2条重复的组合记录(每条request都和那条report配对) - 这时候
COUNT(m2.id)会把这2行里的m2.id都算进去(哪怕是同一个report的id),所以统计出的reports数量就变成了2,而实际只有1条,结果自然就错了。
解决方案1:用条件计数(一次JOIN搞定,效率最高)
不需要多次关联表,直接在COUNT里加CASE判断消息类型——COUNT会自动忽略NULL值,刚好能精准统计每种类型的数量:
SELECT c.id, c.name, COUNT(CASE WHEN m.type = 'request' THEN m.id END) AS requests, COUNT(CASE WHEN m.type = 'report' THEN m.id END) AS reports FROM companies c LEFT JOIN messages m ON m.companies_id = c.id GROUP BY c.id, c.name;
解决方案2:先聚合消息表再JOIN(满足你想用JOIN的需求)
如果坚持要用JOIN的方式,可以先把messages按公司和类型分组统计好数量,再和companies表关联,这样就不会出现笛卡尔积的问题:
SELECT c.id, c.name, COALESCE(m_requests.count, 0) AS requests, COALESCE(m_reports.count, 0) AS reports FROM companies c LEFT JOIN ( SELECT companies_id, COUNT(id) AS count FROM messages WHERE type = 'request' GROUP BY companies_id ) m_requests ON m_requests.companies_id = c.id LEFT JOIN ( SELECT companies_id, COUNT(id) AS count FROM messages WHERE type = 'report' GROUP BY companies_id ) m_reports ON m_reports.companies_id = c.id;
这里用COALESCE是为了把没有对应类型消息的公司的NULL结果转换成0,显示更友好。
小建议
优先选第一种方案哦!它只需要扫描一次messages表,比第二种方案(扫描两次)效率更高,代码也更简洁~
内容的提问来源于stack exchange,提问作者luis.ap.uyen
相关产品推荐
相关产品推荐

