having子句和where有什么区别_mysql语法差异说明

来源:这里教程网 时间:2026-02-28 20:41:44 作者:

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 版本允许(视为对整个结果集做一次隐式分组),但语义模糊、可读性差、迁移风险高 —— 生产环境应避免。

相关推荐