SQL Left join加WHERE多条件丢失0关联左表数据问题求解

问题背景
现有broadcast、contact两张表,需求为统计每个广播对应的收件人数量,要求即使没有对应收件人,也要展示全部广播列表。最初使用如下Left join查询可得到符合预期的结果:
SELECT b.id, b.brl_name, COUNT(c.broadcast_list_id) AS Recepients FROM broadcastlistsms b LEFT JOIN addcontact c ON b.id = c.broadcast_list_id GROUP BY b.id,b.brl_name;
两张表均包含created_by、isdeleted公共字段,isdeleted字段值为1代表对应联系人或广播已被删除。现需要过滤统计:仅统计指定用户创建、未删除的广播,关联统计同用户创建、未删除的联系人数量,仍需保留联系人数为0的广播条目。
使用如下带WHERE条件的查询时,无法返回联系人数为0的广播条目,未达到预期:
SELECT b.id, b.brl_name, COUNT(c.broadcast_list_id) AS Recepients FROM broadcastlistsms b LEFT JOIN addcontact c ON b.id = c.broadcast_list_id WHERE (b.createdby_id = 1 and b.isdeleted = 0) and (c.createdby_id = 1 and c.isdeleted = 0) GROUP BY b.id,b.brl_name;
后续contact表还将新增3个类似isdeleted的标识字段,需要支持按这些字段做条件过滤后再统计计数。
问题原因
左连接(LEFT JOIN)的执行逻辑是:左表数据全部返回,右表匹配不到关联条件的行时,右表字段全部返回NULL。
如果把右表(contact表)的过滤条件写在WHERE子句中,会把右表字段为NULL的行全部过滤掉,本质上把左连接变成了内连接,自然无法保留联系人数为0的广播条目。
正确写法
把右表的过滤条件全部放到LEFT JOIN的ON子句后面,左表的过滤条件可以保留在WHERE中(也可以放到ON里,效果一致),写法如下:
SELECT b.id, b.brl_name, COUNT(c.broadcast_list_id) AS Recepients FROM broadcastlistsms b LEFT JOIN addcontact c ON b.id = c.broadcast_list_id -- 右表所有过滤条件全部写在ON子句中,避免过滤掉左表无匹配的行 AND c.createdby_id = 1 AND c.isdeleted = 0 -- 后续新增的contact表过滤字段,直接在这里追加AND条件即可 -- AND c.xxx_flag = 0 WHERE b.createdby_id = 1 AND b.isdeleted = 0 GROUP BY b.id,b.brl_name;
如果后续contact表新增其他过滤标识字段,直接在JOIN的ON块后面追加对应的AND判断条件即可,不会影响左表广播条目的保留。
补充说明:COUNT()函数统计时会自动忽略NULL值,所以匹配不到联系人的广播,计数会正确返回0,不需要额外做IFNULL类处理。
内容的提问来源于stack exchange,提问作者user19491662
相关产品推荐
相关产品推荐

