HAVING用于过滤聚合结果,必须配合GROUP BY且位于其后;WHERE在聚合前执行,不能使用聚合函数;JOIN类型与条件位置(ON vs WHERE)影响空值处理,需谨慎选择。

JOIN之后不能直接用WHERE过滤聚合结果
很多人写SQL时发现,对关联表做聚合后想筛掉某些分组,比如“只查订单总额超5000的客户”,却在WHERE里写SUM(order_amount) > 5000——这会报错:Invalid use of aggregate function。因为WHERE执行在聚合前,此时SUM()还没算出来。
真正该用的是HAVING,但它必须和GROUP BY配合,且只能出现在GROUP BY之后。所以关键不是“能不能用HAVING”,而是“怎么组织JOIN + GROUP BY + HAVING的顺序”。
正确写法:先JOIN,再GROUP BY主表字段,最后HAVING
假设要查“每个客户名下订单总金额超过5000的订单明细”,需要关联customers和orders表:
SELECT c.customer_name, o.order_id, o.order_amount FROM customers c INNER JOIN orders o ON c.customer_id = o.customer_id GROUP BY c.customer_id, c.customer_name, o.order_id, o.order_amount HAVING SUM(o.order_amount) OVER (PARTITION BY c.customer_id) > 5000;
注意这里用了窗口函数SUM() OVER——因为若只用普通GROUP BY,就无法同时返回单条订单记录(o.order_id)和客户级聚合值。常见错误是强行把所有非聚合字段塞进GROUP BY,导致逻辑失效。
更稳妥的做法分两步:
- 子查询或CTE先算出符合条件的
customer_id列表(用GROUP BY + HAVING) - 主查询用
IN或JOIN关联原始订单表
HAVING和WHERE混用时的执行顺序陷阱
下面这个写法看似合理,实则危险:
SELECT c.customer_name, COUNT(o.order_id) cnt FROM customers c LEFT JOIN orders o ON c.customer_id = o.customer_id WHERE o.status = 'shipped' -- 这里过滤了NULL GROUP BY c.customer_name HAVING cnt > 3;
问题在于:LEFT JOIN后o.status可能为NULL,而WHERE o.status = 'shipped'会把没订单的客户整个剔除(变成INNER JOIN效果)。如果本意是“统计已发货订单数≥3的客户”,没问题;但如果是“统计所有客户中,其已发货订单数≥3者”,就必须把条件移到ON子句里:
- ✅ 正确(保留无订单客户):
LEFT JOIN orders o ON c.customer_id = o.customer_id AND o.status = 'shipped' - ❌ 错误(丢掉无订单客户):
WHERE o.status = 'shipped'
HAVING只管聚合后的结果,它不负责补救WHERE或ON造成的行丢失。
MySQL 5.7 vs 8.0+ 对SELECT字段的严格性影响HAVING可用性
MySQL 5.7默认开启sql_mode=STRICT_TRANS_TABLES,ONLY_FULL_GROUP_BY,这意味着SELECT里的非聚合字段必须全部出现在GROUP BY中。而很多开发者习惯写:
SELECT customer_name, SUM(order_amount) FROM customers c JOIN orders o USING(customer_id) GROUP BY customer_id HAVING SUM(order_amount) > 5000;
这在5.7会报错:customer_name is not in GROUP BY。解决方法只有两个:
- 把
customer_name加进GROUP BY(前提是customer_id和customer_name一一对应) - 用
ANY_VALUE(customer_name)显式声明接受任意值(MySQL 5.7+)
PostgreSQL和SQL Server更严格,不支持ANY_VALUE,必须保证GROUP BY完整性。别指望HAVING能绕过这个底层规则。
复杂点往往不在HAVING本身,而在你是否清楚当前SQL引擎对GROUP BY的容忍边界,以及JOIN类型如何影响空值参与聚合。










