首页/数据/SQL 速查/WHERE 与 HAVING 的分工
聚合与窗口函数54 条

WHERE 与 HAVING 的分工

WHERE 过滤行、HAVING 过滤组:同一条件写在哪一层会影响参与分组的数据量与结果正确性。

SQL 速查数据更新于 2026-10-13

WHERE 与 HAVING 的分工

两者都在过滤,但作用对象不同:WHERE 过滤行,发生在分组与聚合之前;HAVING 过滤组,发生在分组与聚合之后,所以条件里可以写聚合函数。判断一个条件该写哪一层,看它会不会改变参与聚合的数据量:会改变就放 WHERE,不会改变就放 HAVING。同时出现时,先 WHERE 缩小数据集,再 GROUP BY,最后 HAVING 筛组,这个顺序在效率与可读性上都最好。

基本信息

过滤对象WHERE 过滤行,HAVING 过滤组
执行顺序WHERE 早于 GROUP BY,HAVING 晚于 GROUP BY
聚合函数WHERE 不允许写,HAVING 允许写
列别名WHERE 不可用,HAVING 与 ORDER BY 可用
无 GROUP BY 时HAVING 仍生效,整表视为一个分组
适用平台标准 SQL,MySQL 8.0 与 PostgreSQL 一致

典型使用场景

  • 报表分层过滤:先按时间与状态过滤行,再按金额门槛过滤组
  • 统计有效数据:WHERE 先剔除无效记录,聚合结果才可信
  • 筛高频用户:HAVING COUNT(*) >= 5 属于组级条件
  • 排查统计偏差:口径不对时先确认条件写在了哪一层
  • 优化慢报表:把能提前过滤的条件从 HAVING 挪到 WHERE
  • 数据质量检查:HAVING COUNT(*) > 1 找出重复分组

对比示例

对比示例
-- 两种写法结果相同,第一种效率更高
SELECT city FROM users WHERE status = 1 GROUP BY city;
SELECT city FROM users GROUP BY city HAVING MAX(status) = 1;   # 不推荐

-- 两层过滤各司其职
SELECT city, COUNT(*) AS cnt, SUM(amount) AS total
FROM orders
WHERE created_at >= '2024-05-01'     # 行级过滤,减少参与聚合的数据
GROUP BY city
HAVING SUM(amount) > 10000           # 组级过滤
ORDER BY total DESC;

逐项对照

维度WHEREHAVING
过滤对象行分组结果
执行时机分组与聚合之前分组与聚合之后
能否用聚合函数不能可以
能否用 SELECT 别名不能可以
对代价的影响直接减少扫描与聚合量不减少聚合量
典型写法WHERE status = 1HAVING COUNT(*) > 5
把行级条件写进 HAVING 会让全表参与聚合,大表上表现为临时表膨胀与磁盘排序,这是慢报表最常见的结构性问题之一。
ONLY_FULL_GROUP_BY 与 PostgreSQL 都要求 HAVING 里的非聚合条件依赖分组列,写条件时按分组键来组织更稳。
为了省事把条件全塞进 HAVING,会让中间结果集远大于必要规模;先想清楚条件属于行还是组,再决定放哪一层。

实践要点

  • 先写 WHERE 再写 HAVING:过滤顺序决定扫描量
  • HAVING 只放必须依赖聚合结果的条件
  • 报表明细里把两层条件的用途写成注释,方便后续维护
  • 慢报表优先检查是不是把行级条件写进了 HAVING
  • 需要多处复用同一口径时,把它固化到视图或 CTE 里
  • 用 EXPLAIN 确认 WHERE 上的条件确实走了索引

易错点

  • 把行级过滤写进 HAVING,全表参与聚合,代价高且口径容易与预期不符
  • 以为两处写同一条件结果总是一样,忽略 NULL 与聚合语义的差异
  • WHERE 子句里写聚合函数会直接报错,容易被误判成数据库版本问题
  • 忘记 GROUP BY 就使用 HAVING,整表变成一组,结果只剩一行
  • 条件分散在两层且相互矛盾,报表结果自我打架且难以发现

数据来源与参考

  • MySQL 8.0 Reference Manual · HAVING
  • PostgreSQL Documentation · HAVING
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌