HAVING用于过滤GROUP BY后的分组结果,必须位于GROUP BY之后且配合聚合函数使用;WHERE在分组前执行,无法引用COUNT()等聚合值,否则报错。

HAVING 是用来过滤 GROUP BY 后的分组结果的,不是用来替代 WHERE 的。它只能出现在 GROUP BY 之后,且必须配合聚合函数(如 COUNT()、SUM()、AVG())使用。
为什么不能用 WHERE 过滤 COUNT() 结果
WHERE 在分组前执行,此时 COUNT() 等聚合值还没算出来,数据库会直接报错:ERROR: column "xxx" must appear in the GROUP BY clause or be used in an aggregate function。
常见错误写法:
SELECT department, COUNT(*) FROM employees WHERE COUNT(*) > 5 GROUP BY department;
这会失败——COUNT(*) 不允许出现在 WHERE 中。
HAVING 必须跟在 GROUP BY 后面
顺序错了就语法报错。标准顺序是:SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY。
正确写法示例:
SELECT department, COUNT(*) AS cnt FROM employees GROUP BY department HAVING COUNT(*) > 5;
要点:
-
HAVING条件中可直接写聚合函数,如COUNT(*)、AVG(salary) - 也可引用
SELECT中定义的别名(但并非所有数据库都支持,PostgreSQL 支持,MySQL 5.7 默认不支持,8.0+ 支持) - 若同时有
WHERE和HAVING,WHERE先筛行,GROUP BY再分组,HAVING最后筛组
常见误用:把 HAVING 当成 WHERE 的增强版
有人试图用 HAVING 过滤非聚合字段,比如:
SELECT department, AVG(salary) FROM employees GROUP BY department HAVING department = 'Engineering';
这虽然能运行(因为 department 在 GROUP BY 中),但逻辑上等价于 WHERE department = 'Engineering',且性能更差——先分组再过滤,而不是提前过滤掉无关行。
应该写成:
SELECT department, AVG(salary) FROM employees WHERE department = 'Engineering' GROUP BY department;
除非你要结合聚合结果做判断(比如“平均薪资 > 15000 的部门”),否则别在 HAVING 里写非聚合条件。
NULL 和空分组容易被忽略
HAVING 对 NULL 分组值默认不匹配(和 WHERE 一样)。如果 department 有 NULL 值,GROUP BY department 会单独成一组,但 HAVING COUNT(*) > 10 不会自动跳过它——它仍参与计算。
需要显式排除时,加条件:
HAVING department IS NOT NULL AND COUNT(*) > 10
另外,空表或全为 NULL 的分组列,可能返回零行,这不是 bug,是符合 SQL 标准的行为——没分组就没结果可过滤。

















