WHERE 过滤行,HAVING 过滤分组结果
这是最本质的区别:WHERE 在
GROUP BY之前执行,作用对象是原始数据的每一行;HAVING 在
GROUP BY之后执行,作用对象是已经分组并计算完聚合函数(如
COUNT()、
SUM())的结果集。 写
WHERE COUNT(*) > 10会报错 —— 因为
COUNT(*)还没算出来,行都还没分组 写
HAVING COUNT(*) > 10是合法的 —— 分组完成,每组一个计数,可以筛掉人数 ≤10 的组
WHERE排除的行,不参与后续分组;
HAVING排除的是整组,不影响其他组
WHERE 不能用聚合函数,HAVING 必须依赖聚合或分组字段
你不能在
WHERE中写
WHERE AVG(salary) > 8000,MySQL 会直接拒绝解析。而
HAVING不仅允许,而且通常就靠它来实现“哪些部门平均工资超 8k”这类需求。 正确示例:
SELECT dept, AVG(salary) AS avg_sal FROM emp GROUP BY dept HAVING avg_sal > 8000;错误写法:
SELECT dept, AVG(salary) AS avg_sal FROM emp WHERE avg_sal > 8000 GROUP BY dept;(
avg_sal是别名,且出现在
WHERE中,双重非法)
HAVING可以用别名(如
avg_sal),
WHERE不行 —— 因为
SELECT列别名在
WHERE阶段还不可见
性能差异:WHERE 能走索引,HAVING 基本不走
如果过滤条件字段上有索引,放在
WHERE中大概率能命中索引,大幅减少扫描行数;而
HAVING是对内存中已分组的结果再筛,无法利用底层表索引。 想查 “2024 年入职且部门平均薪资 > 15k 的部门”,应把
WHERE hire_date >= '2024-01-01'放前面,先缩小数据集 若错误地写成
HAVING hire_date >= '2024-01-01',不仅语法错(
hire_date未在
GROUP BY中也不聚合),更关键的是:即使能运行,也会全表扫完再分组,再筛 —— 白耗资源 关联查询中,
WHERE先筛再 join,
HAVING是 join 后再筛,前者效率通常高得多
执行顺序决定能否混用 —— 不是“选一个”,而是“各司其职”
标准 MySQL 查询执行顺序是:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT。这意味着你经常需要 WHERE 和 HAVING 同时出现,各自干好自己的活。 典型组合场景:
SELECT dept, COUNT(*) AS cnt, AVG(salary) FROM emp WHERE status = 'active' AND salary > 3000 GROUP BY dept HAVING cnt >= 5 AND AVG(salary) > 12000 ORDER BY cnt DESC;这里:
WHERE确保只统计在职且底薪够高的员工(影响分组基数);
HAVING确保只返回人数 ≥5 且平均薪资 >1.2w 的部门(影响最终输出行数) 漏掉
WHERE可能导致无效数据进分组;漏掉
HAVING可能返回大量无业务意义的分组结果 真正容易被忽略的点是:**HAVING 不是 WHERE 的“升级版”,它是 GROUP BY 的配套子句**。没有
GROUP BY却写
HAVING,虽然某些 MySQL 版本允许(视为对整个结果集做一次隐式分组),但语义模糊、可读性差、迁移风险高 —— 生产环境应避免。
