SQL

SQL 知识量:22 - 44 - 129

11.1 使用子查询><

使用子查询进行过滤- 11.1.1 -

子查询就是嵌套在其他查询中的查询。

例如:有一个学生表(student)和选课表(course),学生表中包含学生的基本信息,如下所示:

+----+--------+-----+--------+
| id | name   | age | sex    |
+----+--------+-----+--------+
|  1 | Susan  |  11 | female |
|  2 | Jame   |  12 | male   |
|  3 | Bob    |  11 | male   |
|  4 | Robot  |  10 | male   |
|  5 | Jen    |  11 | female |
|  6 | Toney  |  10 | male   |
|  7 | Jack   |  13 | male   |
|  8 | Alice  |  10 | female |
|  9 | Bonnie |  11 | male   |
| 10 | Ella   |  12 | female |
+----+--------+-----+--------+

选课表中包含选课的学生id和选择的课程id,如下所示:

+----+------------+-----------+
| id | id_student | id_lesson |
+----+------------+-----------+
|  1 |          1 |         1 |
|  2 |          5 |         3 |
|  3 |          2 |         1 |
|  4 |          4 |         1 |
|  5 |          6 |         1 |
|  6 |          1 |         2 |
|  7 |          3 |         2 |
|  8 |          4 |         2 |
|  9 |          5 |         2 |
| 10 |          2 |         3 |
| 11 |          4 |         3 |
| 12 |          6 |         3 |
+----+------------+-----------+

现在,查询所有选了课的学生姓名。一般的思路是:

  1. 先在选课表中查询出选课学生的id。

  2. 再在学生表中查询出id与选课学生id相同的学生信息。

利用子查询进行操作的SQL语句为:

select name from student where id in (select distinct id_student from course);

结果:

+-------+
| name  |
+-------+
| Susan |
| Jame  |
| Bob   |
| Robot |
| Jen   |
| Toney |
+-------+

由上面的SQL语句可知,在子查询时,第一步查询作为子查询放置于第二步查询的in操作符后面。在SQL运行时,DBMS总是先运行内层子查询,再运行外层查询。

需要注意的是:

  • 作为子查询的select语句只能查询单个列。

  • 嵌套的子查询越多,数据库性能下降越厉害,因此,尽可能减少嵌套。

在计算字段使用子查询- 11.1.2 -

使用子查询的另一种方法是创建计算字段。

例如查询学生姓名和已选课程的数量,按照学生姓名排序。这涉及两个表:学生表(student)和选课表(course),SQL语句为:

select name,
       (select count(*) 
       from course 
       where course.id_student=student.id) as course_selected
from student 
order by name;

结果:

+--------+-----------------+
| name   | course_selected |
+--------+-----------------+
| Alice  |               0 |
| Bob    |               1 |
| Bonnie |               0 |
| Ella   |               0 |
| Jack   |               0 |
| Jame   |               2 |
| Jen    |               2 |
| Robot  |               3 |
| Susan  |               2 |
| Toney  |               2 |
+--------+-----------------+

以上语句的关键是子查询的where子句中的course.id_student=student.id,表示这里要比较一下course中的id_student与student中的id是否一致。如果没有这一过滤条件,结果会是一个笛卡尔积,这当然不是正确答案。

在使用多个表时,如果表中的列名相似、容易混淆,则必须使用完全限定列名,具体方法是在列名前加上表的名字,并用点(.)联结列名。