在SQL的数据查询场景中,我们经常需要先对数据做分组聚合,再从分组后的结果中筛选出符合特定条件的数据,这时候就需要用到HAVING子句。HAVING是SQL中专门用于分组后结果筛选的关键字,和WHERE子句的作用逻辑有相似之处,但适用场景完全不同。

HAVING的基本语法
HAVING子句必须和GROUP BY子句搭配使用,不能单独出现,其基本语法结构如下:
SELECT 分组字段, 聚合函数(字段) AS 别名 FROM 表名 [WHERE 筛选条件] GROUP BY 分组字段 HAVING 分组后的筛选条件 [ORDER BY 排序字段];
需要注意,HAVING后面可以跟聚合函数计算结果作为筛选条件,也可以跟分组字段的条件,而WHERE后面不能直接使用聚合函数作为筛选条件,这是两者最核心的区别之一。
HAVING和WHERE的核心区别
很多开发者会混淆这两个子句的使用,我们可以通过下表清晰对比两者的差异:
| 对比项 | WHERE | HAVING |
|---|---|---|
| 作用阶段 | 分组前对原始数据进行筛选 | 分组后对聚合结果进行筛选 |
| 是否支持聚合函数 | 不支持 | 支持 |
| 是否必须搭配GROUP BY | 不需要 | 必须搭配GROUP BY(除非使用聚合函数但不分组,这种情况较少见) |
HAVING的常见使用场景
场景1:筛选聚合结果符合条件的数据
比如我们需要查询订单表中,总订单金额超过1000的用户ID和对应的总订单金额,这时候需要先按用户ID分组计算总金额,再筛选总金额大于1000的记录:
-- 假设订单表名为order_table,字段user_id为用户ID,amount为订单金额 SELECT user_id, SUM(amount) AS total_amount FROM order_table GROUP BY user_id HAVING SUM(amount) > 1000;
场景2:筛选分组后记录数符合条件的数据
比如我们需要查询购买了3件及以上商品的用户ID和对应的商品购买数量,这时候可以用COUNT聚合函数统计每个用户的购买记录数:
-- 假设购买记录表名为purchase_record,字段user_id为用户ID,product_id为商品ID SELECT user_id, COUNT(product_id) AS buy_count FROM purchase_record GROUP BY user_id HAVING COUNT(product_id) >= 3;
场景3:结合WHERE和HAVING实现多层筛选
如果我们需要先过滤掉无效订单,再统计有效订单中总金额超过500的用户,就可以同时使用WHERE和HAVING:
-- 假设订单表中status为订单状态,1代表有效订单 SELECT user_id, SUM(amount) AS valid_total FROM order_table WHERE status = 1 GROUP BY user_id HAVING SUM(amount) > 500;
使用HAVING的注意事项
- HAVING子句必须写在GROUP BY子句之后,ORDER BY子句之前,顺序错误会导致SQL执行报错。
- HAVING后面如果引用字段,必须是SELECT中出现的分组字段或者聚合函数计算结果,不能使用未分组的普通字段。
- 如果需要对HAVING筛选后的结果排序,可以在HAVING之后添加ORDER BY子句,使用聚合函数的别名或者表达式都可以。
实际开发中只要先明确需求是分组前筛选还是分组后筛选,就能快速判断该用WHERE还是HAVING,避免常见的语法错误。