having必须跟在group by后,用于筛选分组结果;单独使用会因未分组而报错;仅能引用分组字段或聚合函数,不可用未分组非聚合列;执行顺序为where→group by→having,应优先用where预过滤。

HAVING 必须跟在 GROUP BY 后面,否则直接报错或结果不可靠;它不是“高级 WHERE”,而是专用于筛组的独立阶段。
为什么单独写 HAVING 会报 ERROR 1140 或 SQLSTATE[HY000]
数据库看到 HAVING 就默认你已完成分组。没写 GROUP BY,它不知道“按什么分组后筛选”。MySQL 报 Mixing of GROUP columns with no GROUP columns is illegal,PostgreSQL 和 SQL Server 多数直接拒绝执行。
- 错误写法:
SELECT dept, AVG(salary) FROM emp HAVING AVG(salary) > 5000 - 正确写法:
SELECT dept, AVG(salary) FROM emp GROUP BY dept HAVING AVG(salary) > 5000 - 极少数例外:全表聚合(如
SELECT COUNT(*) FROM log HAVING COUNT(*) > 1000)虽语法通过,但可读性差、跨库不兼容,建议改用子查询
HAVING 条件里能用什么?不能用什么?
HAVING 的上下文只有两样东西:分组字段(GROUP BY 列)和聚合结果(COUNT(*)、AVG(price) 等)。原始行里的单值字段,比如 name、status、salary,只要没出现在 GROUP BY 里,也未被聚合函数包裹,就根本不存在于 HAVING 执行时的内存结构中。
- ✅ 允许:
HAVING COUNT(*) > 5、HAVING AVG(price) IS NOT NULL AND AVG(price) > 100、HAVING category = 'tech'(前提是category在GROUP BY中) - ❌ 报错:
HAVING status = 'active'(status未分组也未聚合)、HAVING salary > 8000(同理) - ⚠️ 别名陷阱:
SELECT dept, AVG(salary) AS avg_sal FROM emp GROUP BY dept HAVING avg_sal > 5000—— 多数数据库不认avg_sal,得写成HAVING AVG(salary) > 5000
WHERE 和 HAVING 混用时,哪部分该放哪儿?
执行顺序是硬约束:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。把本该提前过滤的条件塞进 HAVING,等于让数据库先分组、再丢弃,纯属浪费 CPU 和内存。
- 放
WHERE(分组前筛行):order_date >= '2025-01-01'、status = 'paid'、price > 0 - 放
HAVING(分组后筛组):COUNT(*) >= 3、SUM(amount) > 5000、MAX(updated_at) > '2025-06-01' - LEFT JOIN 场景要小心:
HAVING COUNT(o.id) >= 3会把零订单用户全踢掉;如果业务要求“保留所有用户”,就得用条件聚合或窗口函数,而不是HAVING
NULL 和浮点精度导致 HAVING 漏判怎么办?
聚合结果为 NULL(比如某组所有 price 都是 NULL),AVG(price) > 100 判定为 UNKNOWN,该组被跳过;COUNT(*) > 0 却仍会保留(因为计数非空)。不同数据库对 NULL 的三值逻辑处理有细微差异,浮点运算还可能因舍入误差导致边界值漏判。
- 显式处理
NULL:HAVING AVG(price) IS NOT NULL AND AVG(price) > 100 - 语义更清晰的计数:
COUNT(col)统计非空值个数,COUNT(*)统计所有行(含NULL) - 避免浮点误差:
SELECT ROUND(AVG(score), 2) AS avg_score ... HAVING ROUND(AVG(score), 2) > 4.5,别依赖别名
最常被忽略的点是:HAVING 不走索引,它只在内存里对已算好的聚合结果做判断。再快的 HAVING 也救不了没用 WHERE 预筛的大表 —— 分组本身已是重操作,别让它扛本不该扛的量。











