文章目录
3.4 嵌套子查询
在SQL查询中,一个
SELECT ...
FROM ...
WHERE ...
具体表现在如下几个方面:
- 元素与集合间的属于关系
- 集合之间的包含和相等关系
- 集合的存在关系
- 元素与集合元素之间的比较关系
嵌套查询分为相关子查询和非相关子查询
- 非相关子查询指子查询的结果不依赖于上层查询
- 相关子查询指当上层查询的元组发生变化时,其子查询必须重新执行
注意:SQL允许多层嵌套子查询,但在子查询中不允许使用ORDER BY子句,该子句仅用于最后结果排序。
3.4.1 使用IN的子查询
单嵌套例子
--[例3.43] 查询选修过课程的学生姓名。
--本例查询的含义是:
--在学生表Student中,将学号出现在成绩表Score中(表明该学生选修过课程)的学生姓名查询出来
SELECT studentName
FROM Student
WHERE Student.studentNo IN --其中Student.studentNo为元素,IN为"属于"
(SELECT Score.studentNo FROM Score)
--嵌套语句“SELECT Score.studentNo FROM Score”的查询结果为选修过课程的所有学生的学号集合
从Student表取出元组逐一与子嵌套表的结果集合比较,在则作为查询结果,否则丢弃,直到Student表为空。
具体看图
多重嵌套例子
--[例3.44] 查找选修过课程名中包含“系统”的课程的同学学号、姓名和班级编号。
SELECT studentNo, studentName, classNo
FROM Student
WHERE studentNo IN
( SELECT studentNo FROM Score
WHERE courseNo IN
( SELECT courseNo FROM Course
WHERE courseName LIKE '%系统%' )
)
-- 等价于
SELECT studentNo, studentName, classNo
FROM Student
WHERE studentNo IN
( SELECT studentNo
FROM Score b, Course c
WHERE b.courseNo=c.courseNo
AND courseName LIKE '%系统%'
)
--等价于
SELECT DISTINCT studentNo, studentName, classNo
FROM Student a, Score b, Course c
WHERE a.studentNo=b.studentNo
AND b.courseNo=c.courseNo
AND courseName LIKE '%系统%'
多重嵌套从最底层开始执行,执行过程跟单嵌套一样
--[例3.45] 查找同时选修过“计算机原理”和“高等数学”两门课程的同学学号、姓名以及该同学所选修的所有课程的课程名和相应成绩,按学号(升序)、成绩(降序)排序输出。
SELECT a.studentNo, studentName, courseName, score
FROM Student a, Course b, Score c
WHERE a.studentNo=c.studentNo AND b.courseNo=c.courseNo
-- 选修过“计算机原理”课程的学号,使用双重嵌套,也可以用单嵌套利用等值连接SELECT studentNo FROM Score x, Course y WHERE x.courseNo=y.courseNo AND courseName='计算机原理')
AND a.studentNo IN
( SELECT studentNo FROM Score
WHERE courseNo IN
( SELECT courseNo FROM Course
WHERE courseName='计算机原理' ) )
-- 选修过“高等数学”课程的学号
AND a.studentNo IN
( SELECT studentNo FROM Score
WHERE courseNo IN
( SELECT courseNo FROM Course
WHERE courseName='高等数学' ) )
ORDER BY a.studentNo, score DESC
如果这道题变成查找同时选修过“计算机原理”和“高等数学”两门课程的同学学号、姓名以及所选修的这两门课程的课程名和相应成绩,按学号(升序)、成绩(降序)排序输出。
那要在WHERE子句中再加一句AND ( b.courseName=‘高等数学’ OR b.courseName=‘计算机原理’ ),相当于在所有课程选出来之后挑选高等数学的还有计算机原理的
3.4.2 使用比较运算符的子查询
--[例3.47] 查询所选修课程的成绩大于所有002号课程成绩的同学学号及相应课程的课程号和成绩。
SELECT studentNo, courseNo, score
FROM Score
WHERE score>ALL
( SELECT score
FROM Score
WHERE courseNo='002' )
--[例3.48] 查询成绩最高分的学生的学号、课程号和相应成绩
SELECT studentNo, courseNo, score
FROM Score
WHERE score=( SELECT max(score)
FROM Score )
聚合函数注意点
聚合函数可直接用在HAVING子句中(如例3.35)
聚合函数也可用于子查询中(如例3.48),
聚合函数不可以直接使用在WHERE子句中。如
SELECT *
FROM Score
WHERE score=max(score) ×
*3.4.3 使用存在量词EXISTS的子查询
- 一是存在量词,使用谓词EXISTS表示(在WHERE子句中使用谓词EXISTS用来判断其后的子查询的结果集合中是否存在元素)
- 二是全称量词,转化通过NOT EXISTS谓词来实现。(双重否定为肯定)
谓词EXISTS大量用于相关子查询中
--[例3.51] 查询选修了所有课程的学生姓名。
SELECT studentName
FROM Student x
WHERE NOT EXISTS
( SELECT * FROM Course c
WHERE NOT EXISTS
--判断学生x.studentNo没有选修课程c.courseNo
( SELECT * FROM Score
WHERE studentNo=x.studentNo
AND courseNo=c.courseNo )
)
3.5 集合查询
并UNION
--[例3.57] 查询“信息管理学院”1999年出生的同学的学号、出生日期、班级名称和所属学院以及“会计学院”1998年出生的同学的学号、出生日期、班级名称和所属学院。
SELECT studentNo, birthday, className, institute
FROM Student a, Class b
WHERE a.classNo=b.classNo AND year(birthday)=1999
AND institute='信息管理学院'
UNION
SELECT studentNo, birthday, className, institute
FROM Student a, Class b
WHERE a.classNo=b.classNo AND year(birthday)=1998
AND institute='会计学院'
交INTERSECT
--[例3.58] 查询同时选修了“001”号和“005”号课程的同学的学号和姓名
SELECT a.studentNo, studentName
FROM Student a, Score b
WHERE a.studentNo=b.studentNo AND courseNo='001'
INTERSECT
SELECT a.studentNo, studentName
FROM Student a, Score b
WHERE a.studentNo=b.studentNo AND courseNo='005'
差EXCEPT
--[例3.59] 查询没有选修“计算机原理”课程的同学的学号和姓名。
SELECT studentNo, studentName
FROM Student
EXCEPT
SELECT DISTINCT a.studentNo, studentName
FROM Student a, Score b, Course c
WHERE a.studentNo=b.studentNo
AND b.courseNo=c.courseNo
AND courseName='计算机原理'