目录
嵌套查询
1.带有IN谓词的子查询
相关子查询和不相关子查询
2.带有比较运算符的子查询
3.带有ANY(SOME)或ALL谓词的子查询
4.带有EXISTS谓词的子查询
[例 3.55] 查询与“刘晨”在同一个系学习的学生。
第一种方法:分布进行查询
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 = '刘晨';
[例 3.56]查询选修了课程名为“信息系统”的学生学号和姓名
select Sno,Sname
from Student -- 最后在Student中取出Sno 和 Sname
where Sno in
(select Sno
from SC --然后在SC关系中找到 与找到的课程号相符的
where Cno in
(select Cno
from Course
where Cname = '信息系统' --先在Course中找到”信息系统的课程号
)
);
用连接查询实现
select Student.Sno,Sname
from Student,Course,SC
where Student.Sno = SC.Sno and
SC.Cno =Course.Cno and Course.Cname= '信息系统';
注:select Sno。。。会提示列名’Sno'不明确 是因为 多个表中都有Sno 需要指明你要查询的表
不相关子查询:子查询的查询条件不依赖于父查询
SELECT Sno, Sname, Sdept
FROM Student
WHERE Sdept IN
(SELECT Sdept
FROM Student
WHERE Sname= ' 刘晨 ');
相关子查询:子查询的查询条件依赖于父查询
由外向里
①取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表
②再取外层表的下一个元组
③重复这一过程,直至外层表全部检查完为止
[例 3.57 ]找出每个学生超过他选修课程平均成绩的课程号。
select Sno,Cno
from SC x
where Grade >=(select avg(Grade)
from SC y
where y.Sno = x.Sno);
Q:哪里体现了选修?
在[例 3.55]中,由于一个学生只可能在一个系学习,则可以用 = 代替IN
select Sno,Sname,Sdept
from Student
where Sdept = (select Sdept
from Student
where Sname = '刘晨');
带有AN使用ANY或ALL谓词时必须同时使用比较运算
语义为:
> ANY 大于子查询结果中的某个值
> ALL 大于子查询结果中的所有值
< ANY 小于子查询结果中的某个值
< ALL 小于子查询结果中的所有值
>= ANY 大于等于子查询结果中的某个值
>= ALL 大于等于子查询结果中的所有值
[例 3.58] 查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄
select Sname,Sage
from Student
where Sage'CS';
select Sname,Sage
from Student
where Sage <
(select max(Sage)--任意一个小 比最大的小就可以了
from Student
where Sdept = 'CS')
and Sdept <>'CS';
[例 3.59] 查询非计算机科学系中比计算机科学系所有学生年龄都小的学生姓名及年龄。
-用all
select Sname,Sage
from Student
where Sage'CS';
-用聚集函数
select Sname,Sage
from Student
where Sage< --比所有都小 需要比最小值小
(select min(Sage)
from Student
where Sdept = 'CS')
and Sdept <> 'CS';
由EXISTS引出的子查询,其目标列表达式通常都用 * ,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义。
[例 3.60]查询所有选修了1号课程的学生姓名。
select Sname
from Student
where exists --取满足条件的Student.Sname
(select *
from SC
where Sno=Student.Sno and Cno = '1'); --在Student中依次取每个元组的Sno 对应SC表的并且 其Cno =1
[例 3.61] 查询没有选修1号课程的学生姓名。
select Sname
from Student
where not exists --当存在是返回的false 也就是不满足时是true
(select *
from SC
where Sno = Student.Sno and Cno = '1');
一些带EXISTS或NOT EXISTS谓词的子查询不能被其他形式的子查询等价替换
所有带IN谓词、比较运算符、ANY和ALL谓词的子查询
都能用带EXISTS谓词的子查询 等价替换
[例 3.55]查询与“刘晨”在同一个系学习的学生。
select Sno,Sname,Sdept
from Student S1
where exists --存在和刘晨Sdept一样的学生
(select *
from Student S2
where S2.Sdept = S1.Sdept and
S2.Sname = '刘晨');
用EXISTS / NOT EXISTS实现全称量词
[例 3.62] 查询选修了全部课程的学生姓名。(转义后的表达:没有一门课程是他不选修的)
select Sname
from Student
where not exists -- 内层返回了false 本层返回true 即得到了没有一门没选修的同学
(select *
from Course
where not exists -- 选修了就返回false 没选修返回true 最后说明这位同学有没选修的
(select *
from SC
where Sno = Student.Sno
and Cno = Course.Cno
)
);
[例 3.63]查询至少选修了学生201215122选修的全部课程的学生号码。
select distinct Sno
from SC SCX
where not exists
(select *
from SC SCY
where SCY.Sno = '201215122' and
not exists --若有122选择了但当前的同学没选择 返回true
(select *
from SC SCZ
where SCZ.Sno = SCX.Sno and
SCZ.Cno = SCY.Cno)
);