嵌套查询
- 一个
SELECT-FROM-WHERE
语句称为一个查询块 - 将一个查询块嵌套在另一个查询块的
WHERE子句
或HAVING短语
的条件中的查询称为嵌套查询
SELECT Sname //外层查询/父查询
FROM Student
WHERE Sno IN
(SELECT Sno //内层查询
FROM SC
WHERE Cno='2');
ORDER BY
对结果排序的查询语句不能出现在嵌套块里,因为是对结果进行排序,只出现在最外层的查询语句中
- 上层的查询块称为外层查询或父查询
- 下层查询块称为内层查询或子查询
- SQL语言允许多层嵌套查询
- 子查询的限制
- 不能使用
ORDER BY子句
- 不能使用
不相关子查询:
子查询的查询条件不依赖于父查询
由里向外逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。
相关子查询:
- 首先取外层查询中表的第一个元组,根据它与内层查询,若WHERE子句返回值为真,则取此元组放入结果表
- 然后再取外层表中的下一个元组
- 重复这一过程,直至外层表全部检查完为止
带有IN谓词的子查询
例1
查询与“刘晨”在同一个系学习的学生。
分步完成
- 确定“刘晨”所在系名
SELECT Sdept
FROM Student
WHERE Sname = '刘晨'
输出结果为CS
- 查找出所有在CS系学习的学生。
SELECT Sno, Sname, Sdept
FROM Student
WHERE Sdept='CS';
Sno | Sname | Sdept |
---|---|---|
201215121 | 李勇 | CS |
201215122 | 刘晨 | CS |
嵌套查询
将第一步查询嵌入到第二步查询的条件中
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN
(SELECT Sdept
FROM Student
WHERE Sname = '刘晨');
用自身连接
SELECT S1.Sno, S1.Sname, S1.Sdept
FROM Student S1, Student S2
WHERE S1.Sdept = S2.Sdept AND S2.Sname='刘晨'
不相关的嵌套查询可以转换成自身连接查询
例2
查询选修了课程名为“信息系统”的学生学号和姓名
嵌套查询
SELECT Sno, Sname
FROM Student
WHERE Sno IN
(SELECT Sno
FROM SC
WHERE Cno IN
(SELECT Cno
FROM Course
WHERE Cname='信息系统'
);
连接查询
SELECT Sno, Sname
FROM Student, SC, Course
WHERE Student.Sno = SC.Sno AND
SC.Cno = Course.Cno AND
Course.Cname='信息系统';
带有比较运算符的子查询
例3
找出每个学生超过它选修平均课程的课程号。
SELECT Sno, Cno
FROM SC x
WHERE Grade >=(SELECT AVG(Grade)
FROM SC y
WHERE y.Sno=x.Sno);
带有ANY(SOME)或ALL谓词的子查询
在谓词逻辑中,还有存在量词和全称量词的概念,在SQL中并没有对应的表达,统一采用“谓词”来表达
方法一:
引入ANY和ALL谓词,其对象为某个查询结果,表示其中任意一个值或者全部值
方法二:
引入EXIST谓词,其对象也是某个查询结果,但表示这个查询结果是否为空,返回真值。
使用ANY或ALL谓词时不许同时使用比较运算
语义为:
表达式 | 含义 |
---|---|
>ANY | 大于子查询结果中的某个值 |
>ALL | 大于子查询结果中的所有值 |
<ANY | 小于子查询结果中的某个值 |
<ALL | 小于子查询结果中的所有值 |
>=ANY | 大于等于子查询结果中的某个值 |
>=ANY | 大于等于子查询结果中的所有值 |
…… | …… |
例4
查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄
用ANY语句实现:
SELECT Sname, Sage
FROM Student
WHERE Sage <ANY (SELECT Sage
FROM Student
WHERE Sdept='CS')
AND Sdept <> 'CS'; /*父查询块中的条件*/
用聚集函数实现:
SELECT Sname, Sage
FFROM Student
WHERE Sage <
(SELECT MAX(Sage)
FROM Student
WHERE Sdept = 'CS')
AND Sdept <> 'CS';
例5
用ALL谓词
SELECT Sname,Sage
FROM Student
WHERE Sage < ALL
(SELECT Sage
FROM Student
WHERE Sdept='CS')
AND Sdept <>'CS';
带有EXISITS谓词的子查询
EXISTS谓词
- 带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”
- 若内层查询结果非空,则外层的WHERE子句返回真值
- 若内层查询结果为空,则外层的WHERE子句返回假值
- 由EXISTS引出的子查询,其目标列表表达式通常用*,因为带EXSITS的子查询只返回真值或假值,给出列名无实际意义。
例6
查询所有选修了1号课程的学生姓名
- 思路分析:
- 本查询涉及Student和SC关系
- 在Student中依次取每个元组的Sno值,用此值去检查SC表
- 若SC中存在这样的元组,其Sno值等于此Student.Sno值,并且其Cno=‘1’,则取此Student.Sname送入结果表。
SELECT Sname
FROM Student
WHERE EXISTS
(SELECT*
FROM SC
WHERE Sno=Student.Sno AND Cno = '1');
查询没有选修1号课程的学生姓名
SELECT Sname
FROM Student
WHERE NOT EXISTS
(SELECT *
FROM SC
WHERE Sno = Student.Sno AND Cno='1');