where 筛选行,having 筛选组;where 在 group by 前执行,不可用聚合函数;having 在 group by 后执行,必须配合聚合或 group by 使用;where 效率更高,应优先用于过滤单行条件。

WHERE 和 HAVING 都是 SQL 中做条件筛选的子句,但它们不是“能换着用”的备选方案,而是分工明确、不可替代的两个环节。核心就一点:WHERE 筛的是行,HAVING 筛的是组——这个区别直接决定了该写在哪、能不能用聚合函数、甚至查得快不快。
执行顺序决定一切
SQL 的标准执行逻辑是:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。这个顺序不是约定俗成,而是强制性的。
- WHERE 在 GROUP BY 之前运行,它看到的是原始表里的每一行,还没分组,也没算 SUM 或 COUNT
- HAVING 在 GROUP BY 之后运行,它看到的是已经分好组、并完成聚合计算的结果(比如每个部门的平均工资、每类商品的销售总额)
- 这意味着:WHERE 排除的行,根本不会进入后续的分组和聚合;而 HAVING 排除的,是整个分组(哪怕组里有100条记录,只要不满足条件,整组消失)
能不能用聚合函数,是硬分界线
这不是语法限制,而是逻辑必然——聚合函数需要多行数据才能算出一个值,而 WHERE 处理的是单行,自然无法引用。
- ✅ 正确:WHERE salary > 5000(查工资高于5000的员工)
- ❌ 错误:WHERE AVG(salary) > 5000(此时还没分组、没算平均值,AVG 无意义)
- ✅ 正确:GROUP BY dept HAVING AVG(salary) > 5000(先按部门分组,再算每组平均值,最后筛掉平均低于5000的部门)
- ✅ 也允许:HAVING COUNT(*) > 10(筛出员工数超10人的部门)
WHERE 更快,别让它干 HAVING 的活
数据库优化的核心原则之一是“尽早减少数据量”。WHERE 能在聚合前就把大量无关行剔除,大幅降低内存和 CPU 开销。
- 例如:查“2025年销售额超10万的地区”。若用 HAVING,数据库得先把所有年份、所有地区的销售额全算一遍,再过滤;而用 WHERE year = 2025 先限定年份,再分组求和,效率高得多
- 常见反模式:把本可用 WHERE 过滤的条件(如 status = 'active'、created_date >= '2025-01-01')挪到 HAVING 里,不仅慢,还容易掩盖逻辑错误
使用位置和依赖关系很实在
WHERE 出现在 FROM 之后、GROUP BY 之前,独立性强,UPDATE/DELETE 也能用;HAVING 必须紧接在 GROUP BY 之后,且几乎总是依赖 GROUP BY 的存在。
- WHERE 可单独存在:SELECT * FROM users WHERE age >= 18
- HAVING 单独出现虽语法允许(某些数据库视整张表为一个组),但语义模糊、易引发误解,不推荐
- 没有 GROUP BY 却写 HAVING,往往说明设计意图没理清——你真想筛“全表聚合结果”吗?还是其实该用 WHERE?










