LEFT JOIN关联查询时如何正确执行COUNT统计(Leetcode1158题)
错误原因
你写的SQL统计结果不对,核心是两个认知偏差:
- SQL子句执行顺序是
FROM/JOIN -> GROUP BY -> SELECT(含聚合、CASE判断),你写的CASE判断逻辑没有正确作用在聚合统计环节 - 你当前的CASE写法逻辑完全不符合需求:
CASE WHEN YEAR(order_date)=2019 THEN COUNT(order_date) ELSE 0 END的实际执行逻辑是:对每个用户分组,先取分组内的一条订单记录(非严格SQL模式下不会报错,返回值不确定)判断年份,如果抽到的那条刚好是2019年的,就统计该用户所有年份的订单总数,否则直接返回0。
你遇到user_id=1返回0的情况,就是分组后取到的判断行是非2019年的订单,直接走了ELSE分支,根本没有统计到2019年的那笔订单。
关联条件加时间筛选生效的原理
LEFT JOIN的ON子句条件是在两表匹配阶段生效的,不会像WHERE子句那样过滤左表的记录:
- 当你在ON后追加
AND YEAR(order_date) = 2019时,Orders表中只有同时满足「买家ID匹配」「订单年份为2019」两个条件的记录,才会被关联到Users表的对应用户行上 - 对应用户的非2019年订单,根本不会出现在关联后的结果集中,关联后这些非2019订单的位置全部为NULL
- 后续按用户分组后,用
COUNT(order_date)统计时,会自动忽略NULL值,最终得到的就是每个用户2019年的有效订单数,没有2019年订单的用户统计结果自然为0,完全符合需求。
注意:不要把时间筛选条件写在WHERE子句里,否则会把关联后订单为NULL的用户(即2019年没下单的用户)全部过滤掉,等价于内连接,会丢失左表的用户数据。
等价正确写法参考
除了在JOIN阶段过滤右表数据,你也可以把年份判断放到COUNT聚合内部,遍历分组内所有订单做统计,结果完全一致:
SELECT U.user_id AS buyer_id, U.join_date, COUNT(CASE WHEN YEAR(O.order_date) = 2019 THEN O.order_date END) AS orders_in_2019 FROM Users U LEFT JOIN Orders O ON U.user_id = O.buyer_id GROUP BY U.user_id, U.join_date;
内容的提问来源于stack exchange,提问作者45_Toshith purkayastha
相关产品推荐
相关产品推荐

