HAVING必须跟在GROUP BY后用于筛选分组后的聚合结果,可含MAX()/MIN()等聚合函数;WHERE不能用聚合函数,因它在分组前执行;单独使用HAVING会报错。

HAVING 不能直接过滤 MAX() 和 MIN() 的单个值
很多人写 HAVING MAX(price) > 100 以为能筛出“最大价格超过 100 的分组”,结果发现语法报错或逻辑不对——这是因为 HAVING 作用于分组后的聚合结果,但 MAX() 和 MIN() 本身不是筛选条件的“目标字段”,而是聚合函数。你真正想表达的,通常是:只保留那些在该分组中存在某个值满足极值条件的组(比如“该品类下有商品价格 > 100”),或者想进一步限制聚合结果本身(比如“只显示最大价格在 50–200 之间的品类”)。
用 HAVING 筛选分组聚合结果的合法写法
HAVING 后必须跟一个布尔表达式,且所有非聚合字段必须出现在 GROUP BY 中;而 MAX()、MIN() 可以直接参与比较,但只能用于已分组上下文。常见正确用法包括:
- 筛选分组的极值范围:
HAVING MAX(price) BETWEEN 50 AND 200 - 排除异常高/低的组:
HAVING MIN(created_at) >= '2024-01-01' - 结合多个聚合判断:
HAVING COUNT(*) > 1 AND MAX(score) = MIN(score)(表示该组所有记录 score 相同)
注意:HAVING MAX(price) > 100 是合法 SQL(只要前面有 GROUP BY),但它判断的是“这个分组的最大 price 是否大于 100”,不是“这个分组里有没有某条 price > 100 的记录”——后者其实等价,因为 MAX(price) > 100 当且仅当至少有一条记录满足 price > 100(假设 price 非空)。所以它其实是可行的,但容易被误读为“对每行 price 做判断”。
为什么 WHERE 不能替代 HAVING 来过滤极值?
WHERE 在分组前执行,无法访问 MAX()、MIN() 这类聚合结果。例如,想查“最大销量 > 1000 的品类”,写 WHERE SUM(sales) > 1000 会报错,因为 SUM() 尚未计算。必须先 GROUP BY category,再用 HAVING SUM(sales) > 1000。
- 错误示范:
SELECT category FROM products WHERE MAX(price) > 100 GROUP BY category→ 语法错误,MAX()不允许在WHERE中 - 正确顺序:先
GROUP BY,再HAVING对聚合结果做布尔判断 - 若需先按单行条件过滤,再算极值,应把条件放在
WHERE:例如WHERE status = 'active',再GROUP BY+HAVING MAX(price) > 100
遇到 NULL 或空分组时 HAVING 的行为
如果某分组内所有 price 都是 NULL,MAX(price) 返回 NULL,而 NULL > 100 结果为 UNKNOWN,该分组会被 HAVING 排除(SQL 的三值逻辑)。这常被忽略,导致预期外的行丢失。
- 安全写法(显式处理 NULL):
HAVING MAX(price) > 100 OR MAX(price) IS NOT NULL不解决,因为MAX(NULL)就是NULL;更合理的是确保数据质量,或用CASE WHEN提前转换 - 检查空分组影响:
SELECT category, COUNT(*), MAX(price) FROM products GROUP BY category HAVING MAX(price) > 100,对比去掉HAVING后的总行数,看是否意外丢弃了全 NULL 分组 - MySQL 8.0+ / PostgreSQL 支持
HAVING COUNT(*) > 0,但意义不大——空分组本就不会出现在GROUP BY结果中
真正容易被绕晕的点是:你以为在“找最大值符合条件的组”,实际是在“根据聚合结果做分组级布尔裁决”,而这个裁决受 NULL、数据分布、甚至 SQL 方言对空集的处理差异影响。动手前先 SELECT category, MAX(price), MIN(price), COUNT(*) FROM ... GROUP BY category 看一眼原始聚合分布,比硬套 HAVING 更可靠。










