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 条件上
