- 连接查询
1.等值与非等值连接查询
2.自身连接
3.外连接
4.多表连接
- 嵌套查询
相关子查询
不相关子查询
1.带有IN谓词的子查询
2.带有比较运算符的子查询
3.带有ANY(SOME)或ALL谓词的子查询
以上就是今天的主要内容!
连接查询
同时涉及两个以上的表的查询
连接条件:用来连接两个表的条件(不写连接条件表示笛卡儿积!)
[<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2>
连接字段:连接条件中的列名称。
注意:连接字段类型必须是可比的,但名字不必相同。
连接操作的执行过程
(1)嵌套循环法(无序,每次都从头找到尾)
(2)排序合并法(先排序,下次从中断点开始找,比1效率高)
——————————————————
等值与非等值连接查询
【例3.49&50】查询每个学生及其选修课程的情况
--等值连接
SELECT Student.*, SC.*
FROM Student, SC
WHERE Student.Sno = SC.Sno;
SELECT *
FROM Student, SC
WHERE Student.Sno = SC.Sno;
--自然连接
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student,SC
WHERE Student.Sno = SC.Sno;
一条SQL语句可以同时完成选择和连接查询。⬇
【例 3.51】查询选修2号课程且成绩在90分以上的所有学生的学号和姓名。
SELECT Student.Sno,Sname
FROM Student,SC
WHERE Student.Sno=SC.Sno AND SC.Cno='2' AND SC.Grade>90;
执行过程:
先从SC中选择出Cno='2’并且Grade>90的元组形成一个中间关系
再和Student中满足连接条件的元组进行连接得到最终的结果关系
自身连接
一个表与其自己进行连接。
注意:需要给表起别名以示区别。所有属性名都是同名属性,因此必须使用“别名”。
【例3.52】查询每一门课的间接先修课(即先修课的先修课)
SELECT FIRST.Cno,SECOND.Cpno
FROM Course FIRST,Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;
外连接(⋈) [像小蝴蝶结耶,但是我写顺手了容易把它写成正无穷]
与普通连接的区别
普通连接操作只输出满足连接条件的元组
外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出。
左外连接(⋉):列出左边关系中所有的元组 。
右外连接(⋊):列出右边关系中所有的元组 。
【例3.53】
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student LEFT OUTER JOIN SC ON(Student.Sno=SC.Sno);
多表查询
【例3.54】查询每个学生的学号、姓名、选修的课程名及成绩
SELECT Student.Sno,Sname,Cname,Grade
FROM Student,SC,Course /*多表连接*/
WHERE Student.Sno=SC.Sno AND SC.Cno=Course.Cno;
SELECT *
FROM Student, SC, Course --多表连接
WHERE Student.Sno = SC.Sno AND SC.Cno = Course.Cno;
嵌套查询
将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询
一个SELECT-FROM-WHERE语句称为一个查询块。
注意⬇
SQL语言允许多层嵌套查询
不能使用ORDER BY子句
不相关子查询:子查询的查询条件不依赖于父查询。
由里向外 逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。(例3.55)
相关子查询:子查询的查询条件依赖于父查询。
首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表
然后再取外层表的下一个元组
重复这一过程,直至外层表全部检查完为止(例3.57)
————————————————
带有IN谓词的子查询
【例3.55】查询与“刘晨”在同一个系学习的学生。
--分步完成
SELECT Sdept
FROM Student
WHERE Sname='刘晨'; /*确定“刘晨”所在系名 结果为: CS*/
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept='CS'; /*查找所有在CS系学习的学生。 */
--不相关子查询实现
SELECT Sno,Sname,Sdept -- 外层查询/父查询
FROM Student
WHERE Sdept IN
(SELECT Sdept
FROM Student
WHERE Sname='刘晨'); --内层查询/子查询 选出CS
--自身连接完成
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 --最后在Student关系中
FROM Student --取出Sno和Sname
WHERE Sno IN
(SELECT Sno --然后在SC关系中找出选
FROM SC --修了3号课程的学生学号
WHERE Cno IN
(SELECT Cno --首先在Course关系中找出
FROM Course --“信息系统”的课程号,为3号
WHERE Cname= '信息系统'
)
);
--连接查询实现(自然连接)
SELECT Student.Sno,Sname
FROM Student,SC,Course
WHERE Student.Sno=SC.Sno AND SC.Cno=Course.Cno AND Course.Cname='信息系统';
带有比较运算符的子查询 (>,<,=,>=,<=,!=或< >)
在【例 3.55】中,由于一个学生只可能在一个系学习,则可以用 = 代替IN :
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept=(SELECT Sdept
FROM Student
WHERE Sname='刘晨');
【例3.57】找出每个学生超过他选修课程平均成绩的课程号。
--相关子查询
SELECT Sno,Cno
FROM SC x
WHERE Grade>=(SELECT AVG(Grade)
FROM SC y
WHERE y.Sno=x.Sno);
执行过程
从外层查询中取出SC的一个元组x,将元组x的Sno值(201215121)传送给内层查询。
执行内层查询,得到值88(近似值),用该值代替内层查询,得到外层查询
执行,循环以上直到SC元组全部处理
带有ANY(SOME)或ALL谓词的子查询
ANY:某个
ALL:所有
= | <>或!= | < | <= | > | >= | |
---|---|---|---|---|---|---|
ANY | IN | – | <MAX | <=MAX | >MIN | >=MIN |
ALL | – | NOT IN | <MIN | <=MIN | >MAX | >=MAX |
【例3.58】查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄
SELECT Sname,Sage
FROM Student
WHERE Sage<ANY(SELECT Sage
FROM Student
WHERE Sdept='CS')
AND Sdept<>'CS'; /*父查询块中的条件 */
执行过程:
(1)首先处理子查询,找出CS系中所有学生的年龄,构成一个集合(20,19)
(2)处理父查询,找所有不是CS系且年龄小于20 或 19的学生
--用聚集函数实现
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 < ALL(SELECT Sage
FROM Student
WHERE Sdept='CS')
AND Sdept<>'CS';
--用聚集函数
SELECT Sname,Sage
FROM Student
WHERE Sage < (SELECT MIN(Sage)
FROM Student
WHERE Sdept='CS')
AND Sdept<>'CS';
天哪,怎么这么多查询啊!这次乖乖的每个都截图了,而且一些对比和过程都在截图里涂鸦标注了,还有一些截图里有对比用的代码没有放到例题下面。这次比上一节课的稍稍难了些,敲代码写博客的时候又理解了下过程,所以这次没有很多废话hhh。
照我目前的情况看吧,应该是你给我一串代码我能很快的告诉你这段代码是干嘛的,但是你告诉我要干嘛让我写代码我能写出来但是应该不能像那么快。原来学语言的时候也有这种情况,还是练得少,所以平时会抽时间看代码滴!
还有就是我发现这段时间一直敲代码我一开始学的概念已经记得不像原来那么清楚了!该去复习一下了!