[mysql基础文档]-28-子查询

引言

select中的子查询类似于英语中"从句"的概念,就是在一条select语句中嵌入另一条子select语句,子select语句的查询结果作为参数返回给外层select,实现数据库中的复合查询。

文章目录

0×1.如何使用where子查询

本文所使用的数据表为"[mysql基础文档]-24-select查询基础"第一部分所创建的cellphone表,请参考:[练习数据表]

在给出查询实例之前,先来了解一下select后跟随的参数先后顺序,如果一条select中携带下面的参数,从左往右书写顺序如下:

where,group by,having,order by,limit

在写语句的过程中必须严格按照顺序,不能limit order by group by这样去写,必须是group by cat_id order by goods_id desc limit 2,3; 严格按照先后顺序;

实例1,查询出cellphone表中goods_id最大的商品

					--goods_id=(括号中就是一条子查询),子查询首先执行,并将其结果赋予给goods_id这个变量
					mysql> select goods_id,goods_name from cellphone where goods_id=(select max(goods_id) from cellphone);
					+----------+------------+
					| goods_id | goods_name |
					+----------+------------+
					|       20 | Huawei7    |
					+----------+------------+

					--还记得以前的拆分方法吗,运行一下子查询,其实上面那条子查询的结果就是20
					--所以上面那条语句就相当于"select goods_id,goods_name from cellphone where goods_id=20;"
					mysql> select max(goods_id) from cellphone;
					+---------------+
					| max(goods_id) |
					+---------------+
					|            20 |
					+---------------+
					

实例2,查询出同类商品(cat_id)中goods_id最大的商品

					--因为子查询得到的是一组数据,所以要用关键字in,相当于遍历一组数列取值,对每一个值,都返回一条记录,本例中goods_id分别取4,17,18,19,20,最后得到下面的结果
					mysql> select goods_id,goods_name,cat_id from cellphone
					    -> where
					    -> goods_id in (select max(goods_id) from cellphone group by cat_id);
					+----------+------------+--------+
					| goods_id | goods_name | cat_id |
					+----------+------------+--------+
					|        4 | MI4        |      1 |
					|       17 | iPhone6s   |      3 |
					|       18 | MX4Pro     |      4 |
					|       19 | GalaxyS6   |      2 |
					|       20 | Huawei7    |      5 |
					+----------+------------+--------+

					--子查询的结果集
					mysql> select max(goods_id) from cellphone group by cat_id;
					+---------------+
					| max(goods_id) |
					+---------------+
					|             4 |
					|            19 |
					|            17 |
					|            18 |
					|            20 |
					+---------------+
					

实例3,MySQL中利用from子查询(准确的讲应该是利用子查询构建一个结果集表,再对这个结果集表进行查询),查询出同类商品(cat_id)中goods_id最大的商品

					--from参数后面需要跟随表名,此例将子查询的结果集定义成tmp表返回给外层select,还记得MySQL对于不确定的多个字段的选取特性吗?本例中子查询将cellphone表使用cat_id排序,如果遇到相同的cat_id则使用goods_id降序排序,这会让tmp表,每组相同cat_id的商品中goods_id最大的排在最上面,tmp表返回给外层select后,外层对tmp使用cat_id进行了分组,当外层select来取值的时候发现,goods_id,goods_name都分别对应了每组cat_id中的4个值,MySQL此时就直接使用排列在最上面的那一条记录中对应字段的值返回显示(仅MySQL,其他数据库会报错)
					mysql> select goods_id,goods_name,cat_id
					    -> from
					    -> (select * from cellphone order by cat_id asc,goods_id desc) as tmp
					    -> group by cat_id;
					+----------+------------+--------+
					| goods_id | goods_name | cat_id |
					+----------+------------+--------+
					|        4 | MI4        |      1 |
					|       19 | GalaxyS6   |      2 |
					|       17 | iPhone6s   |      3 |
					|       18 | MX4Pro     |      4 |
					|       20 | Huawei7    |      5 |
					+----------+------------+--------+

					--大家可以试着运行一下子查询就会明白为什么
					mysql> select * from cellphone order by cat_id asc,goods_id desc;
					

0×2.如何使用exists子查询

为了更好的演示exists查询功能,在qingsword_com数据库中新建另一张表category,存放手机的种类信息,与cellphone表对应

					mysql> create table category(cat_name char(50) not null default '',cat_id tinyint unsigned not null default 0);

					mysql> insert into category values
					    -> ('XiaoMi',1),
					    -> ('Samsung',2),
					    -> ('Apple',3),
					    -> ('Meizu',4),
					    -> ('Huawei',5);

					mysql> select * from category;
					+----------+--------+
					| cat_name | cat_id |
					+----------+--------+
					| XiaoMi   |      1 |
					| Samsung  |      2 |
					| Apple    |      3 |
					| Meizu    |      4 |
					| Huawei   |      5 |
					+----------+--------+
					

实例1,查询出cellphone表中goods_id=20的商品,在category表中的类型名称

					--使用子查询,可以将一个表的查询结果集传递给另一个表处理,实现多表之间的查询关联
					mysql> select cat_name,cat_id
					    -> from category
					    -> where
					    -> cat_id=(select cat_id from cellphone where goods_id=20);
					+----------+--------+
					| cat_name | cat_id |
					+----------+--------+
					| Huawei   |      5 |
					+----------+--------+
					

实例2,利用exists子查询,判断cellphone表中是否存在某个手机类型,如果存在则返回类型名称

					--exists判断括号中的子查询是否能够查到值,查到则返回子查询对应的那一条记录,如果查不到则继续下一条记录查询,比如外层select查询的时候,第一条记录category.cat_id=1,将它赋予子查询cellphone.cat_id=1,此时看子查询的select能否查找到值,如果找到,则根据外层select *(这里是*就是返回全部列信息)返回当前行记录(当前行就是被查询的这一行category.cat_id=1)

					--因为对应每个cat_id,在cellphone表中都存在4条商品记录,所以这里返回的表就是category表的全部内容
					mysql> select * from category
					    -> where exists
					    -> (select * from cellphone where cellphone.cat_id=category.cat_id);
					+----------+--------+
					| cat_name | cat_id |
					+----------+--------+
					| XiaoMi   |      1 |
					| Samsung  |      2 |
					| Apple    |      3 |
					| Meizu    |      4 |
					| Huawei   |      5 |
					+----------+--------+

					--大家可能有一点疑问,这一次的子查询语句单独运行会报错,确实如此,因为category表并没有被引用,只有使用from引用后,才能使用这种"表名.列名"的形式获取值
					mysql> select * from cellphone where cellphone.cat_id=category.cat_id;
					ERROR 1054 (42S22): Unknown column 'category.cat_id' in 'where clause'