1. 前言

在 MySQL 中使用 select 查询语句的时候,一般都会加上 where 语句或者 limit 语句限定查询结果的范围,两种子句都是过滤的作用。另外还有和 group by 语句配合使用的 having 限制条件。区分 where 和 having 语句的作用也是比较基础的题目。

2. where 和 having

面试官提问: 请阐述下在 MySQL 中 where 和 having 关键词有什么区别?

题目解析: 为了更加清楚地阐述两个关键用法的不同,我们还是从实际例子出发。

进入上一节创建的测试数据库:

USE mooc_demo;

然后进入测试数据库,创建 user 表:

USE `mooc_demo`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '数据库主键',
  `username` varchar(32) DEFAULT NULL COMMENT '用户名',
  `password` varchar(32) DEFAULT NULL COMMENT '密码',
  `gender` int(2) DEFAULT NULL COMMENT '1:男性,2:女性',
  `age` int(10) DEFAULT NULL COMMENT '年龄',
  PRIMARY KEY (id) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后再插入一些测试数据:

insert into user (username,password,gender,age) values ('小明','123456',1,20); 
insert into user (username,password,gender,age) values ('小红','123457',2,22); 
insert into user (username,password,gender,age) values ('小王','123458',1,24); 
insert into user (username,password,gender,age) values ('小刘','123459',2,26); 

2.1 where 和 having 都能使用的场景

select username,password,gender,age from user where age >= 20;
select username,password,gender,age from user having age >= 20;

上述两条 sql 都能执行成功,如果 select 之后的字段包含 having 修饰的字段,这种情况下 where 和 having 是等效的。

2.2 只能用 where,不能用 having 的场景

select username,password,gender from user where age >= 20;
select username,password,gender from user having age >= 20;

第一条 sql 执行成功,执行第二条 sql 会报错:ERROR 1054 (42S22): Unknown column 'age' in 'having clause',翻译过来就是 "对于 having 语句,age 字段是未知的"。

having 执行的前置条件是:select xxx,... 筛选出的字段包含 having 修饰的关键词。

两者的执行顺序不同:因为 having 是从前面筛选出来的字段中再进行二次筛选,where 则是针对全表先进行筛选。

2.3 只能用 having,不能用 where 的场景

select count(*),gender,avg(age) as avg_age from user group by gender where avg_age > 20;
select count(*),gender,avg(age) as avg_age from user group by gender having avg_age > 20;

我们的目的是 "按照性别进行分组,统计平均年龄大于 20 的人数、性别和平均年龄"。

但是第一条 sql 执行会报错:ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where avg_age > 20' at line 1,即对于 where 语句,全表并没有 avg_age 平均年龄这个字段,所以会搜索失败。

从上述的实验结果总结来看,where 和 having 的核心区别有三点:

① 使用范围的不同:

  • where:能够用于 select、update、delete 语句;
  • having:只能用于 select 查询语句。

② 执行顺序不同:

  • where 修饰的搜索条件是在分组完成之前执行;
  • having 修饰的搜索条件是在分组完成之后执行。如果一条 sql 语句同时包含 where 和 having 关键词,会先执行 where 搜索,再执行 having 搜索条件。

③ 聚合函数的联合使用:

  • where:不能联合聚合函数(sum、avg、count、max、min 这类)使用;
  • having:能够联合聚合函数使用。

3. 小结

本章节介绍了 where 和 having 语句的用法和不同点,候选人在阐述的时候需要抓住最核心的一点,where 语句在聚合之前筛选数据,having 语句在聚合之后对数据进行筛选,作用在 group by 语句之后。