子查询多用在多表查询中,比如用外键连接的两张表。下面举个例子:
本节用到的两张表:
- 学生信息表:
student_info表
number | name | sex | id_number | department | major | enrollment_time |
---|---|---|---|---|---|---|
20180101 | 杜子腾 | 男 | 158177199901044792 | 计算机学院 | 计算机科学与工程 | 2018-09-01 |
20180102 | 杜琦燕 | 女 | 151008199801178529 | 计算机学院 | 计算机科学与工程 | 2018-09-01 |
20180103 | 范统 | 男 | 17156319980116959X | 计算机学院 | 软件工程 | 2018-09-01 |
20180104 | 史珍香 | 女 | 141992199701078600 | 计算机学院 | 软件工程 | 2018-09-01 |
20180105 | 范剑 | 男 | 181048200008156368 | 航天学院 | 飞行器设计 | 2018-09-01 |
20180106 | 朱逸群 | 男 | 197995199801078445 | 航天学院 | 电子信息 | 2018-09-01 |
- 学生成绩表:
student_score表
number | subject | score |
---|---|---|
20180101 | 母猪的产后护理 | 78 |
20180101 | 论萨达姆的战争准备 | 88 |
20180102 | 母猪的产后护理 | 100 |
20180102 | 论萨达姆的战争准备 | 98 |
20180103 | 母猪的产后护理 | 59 |
20180103 | 论萨达姆的战争准备 | 61 |
20180104 | 母猪的产后护理 | 55 |
20180104 | 论萨达姆的战争准备 | 46 |
现在有这个查询需求:想查询学生信息表中“杜子腾”同学的成绩。可以使用两条查询语句,如下:
# 20180101
SELECT student_number FROM student_info WHERE name = '杜子腾';
SELECT * FROM student_score WHERE student_number = 20180101;
也可以仅写一条SQL语句,即使用子查询,如下:
SELECT * FROM student_score WHERE student_number = (SELECT student_number FROM student_info WHERE name = '杜子腾');
子查询其实就是将两条相关联的查询语句合成一条查询语句,基本上是把其中一条查询语句的结果作为另一条查询语句的操作数,根据上面子查询的例子,介绍一下子查询的相关概念:
- 子查询/内层查询:()里的查询语句称为内层查询,作为外层查询的操作数;
- 外层查询:使用内层查询的结果作为查询操作数的查询称为外层查询;
- 子查询可以嵌套不值不止一个。
1、标量子查询
子查询的结果单纯的是一个数值的子查询称为标量子查询,标量子查询的结果是一个数值,因此可以放在表达式的操作数中,也可以放在查询列表,上面的例子就是个标量子查询。2、列子查询
子查询的结果是一个列的子查询被称为列子查询。
举个例子,想要查询专业是“计算机科学与工程”的同学的科目及对应分数,如果不用子查询,我们需要以下两条SQL语句: ```sql根据专业名称在学生信息表中查询“计算机科学与工程”专业学生的学号
SELECT student_number FROM student_info WHERE major = ‘计算机科学与工程’;
根据上面SQL语句的查询的结果:20190101和20180102,在学生成绩表中再查询
SELECT FROM student_score WHERE student_number = 20180101; SELECT FROM student_score WHERE student_number = 20180102;
用列子查询,SQL语句如下:
```sql
SELECT * FROM student_score WHERE student_number IN (SELECT student_number FROM student_info WHERE major = '计算机科学与工程');
上述列子查询语句中,内层查询语句返回的结果是两个学号20180101和20180102组成的列表,所以外层查询用IN
。
3、行子查询
子查询的结果是一行的子查询称为行子查询。由于结果仅有一行,行子查询的结果集最多仅有一条记录。
举个例子,现在学生成绩表里显示一行“母猪的产后护理”课程学生的分数和课程情况:
SELECT * FROM student_score WHERE (number, subject) = (SELECT number, '母猪的产后护理' FROM student_info LIMIT 1);
结果:
注意上面的SQL
语句里,WHERE
后面等值比较的是一组数,而不是之前的一个数。
4、表子查询
如果子查询结果集中包含多行多列,那么这个子查询也可以被称之为表子查询。
5、EXISTS和NOT EXISTS子查询
有时候使用子查询时,不关心内层查询的具体结果是什么,只关心内层查询的结果集是不是空集,即内层查询有没有查询到满足要求的数据,此时可以用EXISTS
和NOT EXISTS
子查询。EXISTS
和NOT EXISTS
是两个操作符,如下:
操作符 | 示例 | 描述 |
---|---|---|
EXISTS |
EXISTS (SELECT ...) |
当子查询结果集不是空集时表达式为真 |
NOT EXISTS |
NOT EXISTS (SELECT ...) |
当子查询结果集是空集时表达式为真 |
比如想查询某学号的学生成绩,且这个学生的学号要在学生信息表里存在才行,使用EXISTS
的子查询如下:
# 查询的学号:20180108不在学生信息表里,子查询结果为空集
SELECT * FROM student_score WHERE EXISTS(SELECT * FROM student_info WHERE student_info.student_number = '20180108')
6、不相关子查询和相关子查询
6.1 不相关子查询
概念:
内层查询和外层查询不相关的子查询,比如前面的例子里,内层查询都是查询的学生信息表,外层查询是查询的学生成绩表,在查询学生信息表时不影响查询学生成绩表。
6.2 相关子查询
概念:
有时候我们需要在内层查询的语句中引用到外层查询的值,这样的话内层查询就不能当作一个独立的语句去执行,这种子查询被称为相关子查询。
7、同一个表中的子查询
子查询既可以用在多表查询中,又可以用在单表查询中,只是多表查询中用的更多,前面的例子也都是多表查询的子查询例子。
举个例子,比如想查询“论萨达姆的战争准备”这门课程大于该课程平均分的学生成绩,可以在学生成绩表这一张表里使用子查询:
SELECT * FROM student_score WHERE subject = '论萨达姆的战争准备' AND score > (SELECT AVG(score) FROM student_score);
上面例子中总结出的同一个表的子查询有以下几点注意:
- 聚集函数不能在
WHERE
子句中; - 外层查询和内层查询都是针对的同一个表:学生成绩表,相当于给学生成绩表建立了一个副本,内层查询针对的是副本对分数求平均分,外层查询根据内层查询求得的平均分在进行查询。也就是说对同一个表进行子查询,相当于内层查询是针对的表的副本进行查询。