HAVING 是分组后过滤的正确入口,WHERE 在分组前执行故不能用聚合函数;HAVING 可用聚合函数、分组字段及组合表达式,但不可用未分组未聚合的普通列,且条件须写在同一子句中。

WHERE 不能用聚合函数,HAVING 才是分组后过滤的正确入口
WHERE 在分组前执行,无法访问 COUNT()、AVG()、SUM() 等聚合结果;HAVING 则在 GROUP BY 之后运行,专门用来筛选分组后的聚合值。写错位置会导致语法错误或逻辑偏差——比如 WHERE COUNT(*) > 10 直接报错。
HAVING 中能用哪些表达式?不只是聚合函数
HAVING 的判断条件可以包含:
- 聚合函数:
COUNT(*)、AVG(price)、MAX(created_at) - 分组字段本身:
category、status(前提是它出现在GROUP BY中) - 组合表达式:
AVG(score) * COUNT(*) > 100 - 但不能出现未分组也未聚合的普通列,如
WHERE name = 'Alice'那种写法在 HAVING 里依然非法
常见误用:把本该在 WHERE 的条件塞进 HAVING
把可提前过滤的条件(如状态、时间范围)放到 HAVING,会强制数据库先分组再丢弃,白白增加计算量。例如:
SELECT user_id, COUNT(*) FROM orders GROUP BY user_id HAVING status = 'paid' AND COUNT(*) >= 3;
这会先对所有订单分组(包括 status = 'cancelled'),再筛——明显低效。应改为:
SELECT user_id, COUNT(*) FROM orders WHERE status = 'paid' GROUP BY user_id HAVING COUNT(*) >= 3;
注意:WHERE 过滤行,HAVING 过滤组,二者职责分明。
多个 HAVING 条件怎么写?和 WHERE 一样用 AND/OR
HAVING 后接布尔表达式,支持完整逻辑运算:
HAVING COUNT(*) > 5 AND AVG(amount) > 100HAVING MAX(updated_at) > '2024-01-01' OR MIN(created_at)- 括号可提升可读性:
HAVING (COUNT(*) >= 2) AND (SUM(quantity) > 100)
没有单独的 HAVING ... AND HAVING ... 语法,所有条件必须写在同一 HAVING 子句中。
真正容易被忽略的是执行顺序:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。只要记住 HAVING 是“对组说话”,而不是“对行说话”,大部分混淆就自然消解了。










