子查询多用在多表查询中,比如用外键连接的两张表。下面举个例子:
本节用到的两张表:

  • 学生信息表:

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

现在有这个查询需求:想查询学生信息表中“杜子腾”同学的成绩。可以使用两条查询语句,如下:

  1. # 20180101
  2. SELECT student_number FROM student_info WHERE name = '杜子腾';
  3. SELECT * FROM student_score WHERE student_number = 20180101;

也可以仅写一条SQL语句,即使用子查询,如下:

  1. 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;

  1. 用列子查询,SQL语句如下:
  2. ```sql
  3. SELECT * FROM student_score WHERE student_number IN (SELECT student_number FROM student_info WHERE major = '计算机科学与工程');

上述列子查询语句中,内层查询语句返回的结果是两个学号20180101和20180102组成的列表,所以外层查询用IN

3、行子查询

子查询的结果是一行的子查询称为行子查询。由于结果仅有一行,行子查询的结果集最多仅有一条记录。
举个例子,现在学生成绩表里显示一行“母猪的产后护理”课程学生的分数和课程情况:

  1. SELECT * FROM student_score WHERE (number, subject) = (SELECT number, '母猪的产后护理' FROM student_info LIMIT 1);

结果:
image.png
注意上面的SQL语句里,WHERE后面等值比较的是一组数,而不是之前的一个数。

4、表子查询

如果子查询结果集中包含多行多列,那么这个子查询也可以被称之为表子查询

5、EXISTS和NOT EXISTS子查询

有时候使用子查询时,不关心内层查询的具体结果是什么,只关心内层查询的结果集是不是空集,即内层查询有没有查询到满足要求的数据,此时可以用EXISTSNOT EXISTS子查询。
EXISTSNOT EXISTS是两个操作符,如下:

操作符 示例 描述
EXISTS EXISTS (SELECT ...) 当子查询结果集不是空集时表达式为真
NOT EXISTS NOT EXISTS (SELECT ...) 当子查询结果集是空集时表达式为真

比如想查询某学号的学生成绩,且这个学生的学号要在学生信息表里存在才行,使用EXISTS的子查询如下:

  1. # 查询的学号:20180108不在学生信息表里,子查询结果为空集
  2. SELECT * FROM student_score WHERE EXISTS(SELECT * FROM student_info WHERE student_info.student_number = '20180108')

6、不相关子查询和相关子查询

6.1 不相关子查询

概念:
内层查询和外层查询不相关的子查询,比如前面的例子里,内层查询都是查询的学生信息表,外层查询是查询的学生成绩表,在查询学生信息表时不影响查询学生成绩表。

6.2 相关子查询

概念:
有时候我们需要在内层查询的语句中引用到外层查询的值,这样的话内层查询就不能当作一个独立的语句去执行,这种子查询被称为相关子查询。

7、同一个表中的子查询

子查询既可以用在多表查询中,又可以用在单表查询中,只是多表查询中用的更多,前面的例子也都是多表查询的子查询例子。
举个例子,比如想查询“论萨达姆的战争准备”这门课程大于该课程平均分的学生成绩,可以在学生成绩表这一张表里使用子查询:

  1. SELECT * FROM student_score WHERE subject = '论萨达姆的战争准备' AND score > (SELECT AVG(score) FROM student_score);

上面例子中总结出的同一个表的子查询有以下几点注意:

  • 聚集函数不能在WHERE子句中;
  • 外层查询和内层查询都是针对的同一个表:学生成绩表,相当于给学生成绩表建立了一个副本,内层查询针对的是副本对分数求平均分,外层查询根据内层查询求得的平均分在进行查询。也就是说对同一个表进行子查询,相当于内层查询是针对的表的副本进行查询。