SQL语言允许多层嵌套查询,即一个子查询中还可以嵌套其他子查询。需要特别指出的是,子查询的 SELECT语句中不能使用 ORDER BY子句, ORDER BY子句只能对最终查询结果排序。
1.带有IN谓词的子查询
在嵌套查询中,子查询的结果往往是一个集合,所以谓词IN是嵌套查询中最经常使用的谓词
例 3.55 查询与“刘晨”在同一个系学习的学生
(1)确定“刘晨”所在系名
SELECT Sdept
FROM Student
WHERE Sname='刘晨';
(2)查找所有在CS系学习的学生
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept='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.带有比较运算符的子查询
例 3.57 找出每个学生超过他自己选修课程平均成绩的课程号
SELECT Sno,Cno
FROM SC x
WHERE Grade>=(SELECT AVG(Grade) /*某学生的平均成绩*/
FROM SC y
WHERE y.Sno=x.Sno);
x是表SC的别名,又称为元组变量,可以用来表示SC的一个元组。内层查询是求个学生所有选修课程平均成绩的,至于是哪个学生的平均成绩要看参数x.Sno的值,而该值是与父查询相关的,因此这类查询称为相关子查询
理解:
(1) 从外层查询中取出SC的一个元组x,将元组x的Sno值 (201215121)传送给内层查询
SELECT AVG(Grade)
FROM SC y
WHERE y.Sno='201215121';
(2) 执行内层查询,得到值88(近似值,用该值代替内层查询,得到外层查询
SELECT Sno,Cno
FROM SC x
WHERE Grade>=88;
(3) 执行这个查询,得到
(201215121,1)
(201215121,3)
然后外层查询取出下一个元组重复做上述①至步骤的处理,直到外层的SC元组全部处理完毕。结果为
3.带有ANY(SOME)或ALL谓词的子查询
= | <>或!= | < | <= | > | >= | |
ANY | IN | - - | <MAX | <=MAX | >MIN | >=MIN |
ALL | - - | NOT IN | <MIN | <=MIN | >MAX | >=MAX |
例 3.59 查询非机算机科学系比计算机科学系所有学生年龄都小的学生姓名及年龄
SELECT Sname,Sage
FROM Student
WHERE Sage<ALL
(SELECT Sage
FROM Student
WHERE Sdept='CS')
AND Sdept<>'CS';
关系数据库管理系统执行此查询时,首先处理子査询,找出CS系中所有学生的年龄构成一个集合(20,19)。然后处理父查询,找所有不是CS系且年龄既小于20,也小于19的学生。查询结果为
用聚集函数的方法:
SELECT Sname,Sage
FROM Student
WHERE Sage<
(SELECT MIN(Sage)
FROM Student
WHERE Sdept='CS')
AND Sdept<>'CS';
4.带有EXISTS谓词的子查询
带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”
例 3.62 查询选修了全部课程的学生姓名
//即没有一门课程是他不选的
SELECT Sname
FROM Student
WHERE NOT EXISTS
(SELECT*
FROM Course
WHERE NOT EXISTS
(SELECT*
FROM SC
WHERE Sno=Student.Sno AND Cno=Course.Cno));
还没弄懂,弄懂再补
例 3.63 查询至少选修的学生201215122选修的全部课程的学生号码
//不存在这样的课程y,学生201215122选修的y,而学生x没有选
SELECT DISTINCT Sno
FROM SC SCX
WHERE NOT EXISTS
(SELECT*
FROM SC SCY
WHERE SCY.Sno='201215122' AND
NOT EXISTS
(SELECT*
FROM SC SCZ
WHERE SCZ.Sno=SCX.Sno AND SCZ.Cno=SCY.Cno));
同上