统计部门人数,顺手写了 SELECT dept, COUNT(*) FROM staff WHERE COUNT(*) > 5 GROUP BY dept,MySQL 抛出 1111 Invalid use of group function。WHERE 在分组前跑,那时候还没有 COUNT,过滤聚合结果只能交给 HAVING。这是典型的 sql having 位置问题。

HAVING 在 GROUP BY 之后生效

执行顺序大致是 FROM、WHERE、GROUP BY、HAVING、SELECT、ORDER BY。WHERE 筛行,HAVING 筛组。把条件挪过去:SELECT dept, COUNT(*) AS cnt FROM staff GROUP BY dept HAVING COUNT(*) > 5,语句就正常了。没有 GROUP BY 时,整张表被当成一个组,SELECT COUNT(*) FROM orders HAVING COUNT(*) > 100 也合法,只是这种判断多数放在程序里更清楚。

别名能不能用,看数据库

MySQL 的 HAVING 可以直接引用 SELECT 里的别名,写 HAVING cnt > 5 没问题。PostgreSQL 和标准 SQL 不认这个别名,得重复写聚合函数,或者外面再套一层子查询。SQL Server 同样不支持。要跨库运行的 SQL,老实写 COUNT(*),少踩坑。

SELECT 里的非聚合列才是大坑

SELECT dept, name, COUNT(*) FROM staff GROUP BY dept,在 MySQL 5.7 默认的 ONLY_FULL_GROUP_BY 下会报 1055。有人把 sql_mode 里的这一项关掉,语句能跑,但 name 取到的是组里随机的某一行,数据看着对,实际没法解释。要么把 name 放进 GROUP BY,要么用 MAX(name) 明确取值规则。

性能上也要注意,HAVING 是分组之后才过滤。状态、日期这类单行条件尽量写在 WHERE,先缩小数据量再分组,扫描行数会少很多。HAVING 留给 COUNT、SUM、AVG 这种算完才知道结果的条件。

判断标准很简单:条件里带聚合函数,用 HAVING;只跟单行字段有关,用 WHERE。sql having 写错,十有八九是位置放反了,先看执行顺序再改。