MySQL中HAVING子句疑问:SUM(oscars)未在SELECT却不报错?
MySQL 8.0中HAVING子句的使用疑问
先明确你的问题场景:
你需要从moviesInfo表中筛选出满足两个条件的导演:
- 执导过2000年之后的电影
- 这些电影的奥斯卡总获奖数超过2
结果按导演名升序排列。
你的初始代码:
SELECT director FROM moviesInfo GROUP BY director HAVING (year > 2000 AND SUM(oscars) > 2) ORDER BY director ASC;
报错Unknown column 'year' in 'having clause',而正确代码:
SELECT director FROM moviesInfo WHERE year > 2000 GROUP BY director HAVING SUM(oscars) > 2 ORDER BY director ASC;
能正常运行,你疑惑的点是:oscars列没出现在SELECT子句中,为什么SQL解释器没报错?
核心原因:HAVING子句的规则并非“必须包含SELECT里的列”
你之前查到的解释不准确,正确的规则是:
HAVING子句可以自由使用聚合函数,不管聚合函数的参数列是否在SELECT中。
聚合函数(比如SUM(oscars))是对分组内的所有记录计算得出的结果,它的合法性只和分组逻辑有关,和SELECT是否包含该列完全无关。比如这里SUM(oscars)是统计每个导演旗下所有符合条件的电影的奥斯卡总数,只要表中有oscars列,就能正常计算,不需要把oscars放到SELECT里。HAVING子句不能直接引用非聚合的单个列(比如
year),除非该列在GROUP BY子句中
当你按director分组后,每个分组里可能包含多部电影,每部电影的year可能不同。此时HAVING里直接写year > 2000,数据库无法确定要用分组里哪一部电影的year来判断条件,所以会报错。而你的正确代码用WHERE year > 2000,是先过滤掉所有2000年及之前的电影,再对剩下的记录按导演分组,这才是符合逻辑的行级过滤操作。
补充:WHERE和HAVING的本质区别
WHERE是行级过滤:在分组前就筛选出符合条件的记录,只对满足条件的记录进行后续分组计算,效率更高。HAVING是分组级过滤:在分组完成后,基于聚合结果筛选符合条件的分组,只能用聚合函数或GROUP BY中包含的列作为判断条件。
内容的提问来源于stack exchange,提问作者Yiwei Jiang
相关产品推荐
相关产品推荐

