HAVING子句用于分组后筛选,必须配合GROUP BY使用,可引用聚合函数或列别名;WHERE在分组前过滤且不支持聚合函数,执行顺序为FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY。

MySQL 中的 HAVING 子句用于对分组后的结果进行筛选,它必须配合 GROUP BY 使用,作用对象是分组聚合后的数据,而不是原始行记录。
HAVING 和 WHERE 的核心区别
WHERE 在分组前过滤行,不能用聚合函数;HAVING 在分组后过滤组,可以使用 COUNT()、SUM()、AVG() 等聚合函数。
- WHERE 条件不支持
SELECT中定义的别名(除非在支持的 MySQL 版本中且别名已明确声明) - HAVING 可以直接引用聚合函数或
SELECT中的列别名(推荐用别名提升可读性) - 执行顺序:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
基本 HAVING 语法结构
典型写法如下:
SELECT column, COUNT(*) AS cnt FROM table_name GROUP BY column HAVING cnt > 10;
注意:
- GROUP BY column 是必需的,否则 HAVING 失去意义(全表被当作一个组)
- HAVING cnt > 10 中的 cnt 是 SELECT 中定义的别名,MySQL 允许这样写(5.7.5+ 默认启用 sql_mode=ONLY_FULL_GROUP_BY 时需确保语义合法)
常见实用场景举例
查出订单总数超过 5 笔的客户ID:
SELECT customer_id, COUNT(*) AS order_count FROM orders GROUP BY customer_id HAVING order_count >= 5;
找出平均价格高于 100 元的商品类别:
SELECT category, AVG(price) AS avg_price FROM products GROUP BY category HAVING avg_price > 100;
筛选出有至少 2 个不同状态的用户(假设 status 字段存在重复值):
SELECT user_id FROM user_logs GROUP BY user_id HAVING COUNT(DISTINCT status) >= 2;
注意事项与避坑提示
- 单独写
HAVING不加GROUP BY会把整张表当做一个组处理,慎用(如SELECT COUNT(*) HAVING COUNT(*) > 100是合法但少见的用法) - 在严格模式下,
SELECT列表中的非聚合字段必须出现在GROUP BY中,否则报错 - HAVING 条件中若混用 WHERE 过滤逻辑(如日期范围),建议优先用 WHERE 先缩小数据集,再 GROUP BY + HAVING,提升性能
- 索引对 HAVING 本身无直接加速作用,优化重点仍在 GROUP BY 字段和前置 WHERE 条件上










