一、连接查询
连接查询:同时涉及两个以上的表的查询
[<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2>
连接字段:连接条件中的列名称
如:Sno为上面例子中的连接字段
注意:连接字段类型必须是可比的,但名字不必相同
1.等值与非等值连接查询 (等值连接:连接运算符为=
)
[例 3.49] 查询每个学生及其选修课程的情况
SELECT Student.*, SC.*
FROM Student, SC
WHERE Student.Sno = SC.Sno;
相当于对比关系代数中的等值连接,通过学生学号将Student表与SC表连接起来。
[例 3.50] 对[例 3.49]用自然连接完成(即等值连接之后要去除相同的属性列)
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中满足连接条件的元组进行连接得到最终的结果关系
2.自身连接
自身连接:一个表与其自己进行连接
需要给表起别名以示区别
所有属性名都是同名属性,因此必须使用**“别名”**
[例 3.52]查询每一门课的间接先修课(即先修课的先修课)
SELECT FIRST.Cno, SECOND.Cpno
FROM Course FIRST, Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;
就拿这张表来说,4号课对应的先行课是2,而2号课对应的先行课是3,那么3就是4号课的间接先行课。
3.外连接
外连接与普通连接的区别:
普通连接操作只输出满足连接条件的元组
外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出
[例 3. 53] 改写[例 3.49]
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student LEFT OUT JOIN SC ON (Student.Sno=SC.Sno);
如果运行有误,将out去掉即可。
外连接将一些内容为空的数据也显示出来了,这是和普通连接不同的地方。
4、多表连接(多表连接:两个以上的表进行连接
)
[例3.54]查询每个学生的学号、姓名、选修的课程名及成绩
SELECT Student.Sno, Sname, Cname, Grade
FROM Student, SC, Course /*多表连接*/
WHERE Student.Sno = SC.Sno
AND SC.Cno = Course.Cno;
5、嵌套查询
①、一个SELECT-FROM-WHERE语句称为一个查询块
②、将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询称为嵌套查询
注意:子查询不能使用ORDER BY子句
不相关子查询:子查询的查询条件不依赖于父查询,即内层查询和外层查询没有直接关系,互不影响
相关子查询:子查询的查询条件依赖于父查询,例如,
SELECT Sno, Cno
FROM SC x
WHERE Grade >=(SELECT AVG(Grade)
FROM SC y
WHERE y.Sno=x.Sno);
内层查询和外层查询都涉及到了x表。
①.带有IN谓词的子查询
[例 3.55] 查询与“刘晨”在同一个系学习的学生。
这里有三种方法。
第一种方法:分步完成
① 确定“翠花”所在系名
SELECT Sdept
FROM Student
WHERE Sname= ' 翠花 ';
结果为: CS
② 查找所有在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= ' 翠花 ');
第三种方法:用自身连接完成[例 3.55]查询要求
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
WHERE Sno IN
(SELECT Sno
FROM SC
WHERE Cno IN
(SELECT Cno
FROM Course
WHERE Cname= '信息系统'
)
);
先在Course表中找到信息系统的课程号,再在SC表中找到选了3的学生学号,最后在Student表中找到对应的学生学号和姓名。
②.带有比较运算符的子查询
当能确切知道内层查询返回单值时,可用比较运算符(>,<,=,>=,<=,!=或< >)
[例 3.57 ]找出每个学生超过他选修课程平均成绩的课程号。
SELECT Sno, Cno
FROM SC x
WHERE Grade >=(SELECT AVG(Grade)
FROM SC y
WHERE y.Sno=x.Sno);
求出每个学生的平均成绩,在与他自己的每一科成绩比较。
③.带有ANY(SOME)或ALL谓词的子查询
使用ANY或ALL谓词时必须同时使用比较运算
语义为:
> ANY 大于子查询结果中的某个值
> ALL 大于子查询结果中的所有值
< ANY 小于子查询结果中的某个值
< ALL 小于子查询结果中的所有值
>= ANY 大于等于子查询结果中的某个值
>= ALL 大于等于子查询结果中的所有值
[例 3.58] 查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄
SELECT Sname,Sage
FROM Student
WHERE Sage < ANY (SELECT Sage
FROM Student
WHERE Sdept= ' CS ')
AND Sdept <> ‘CS ' ; /*父查询块中的条件 */
大于任意一个是指大于表中最大的数据,大于all是指大于所有数据。
[例 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 ';
总的来说,练习的比较顺利,关于嵌套部分有一点绕,需要多练习才能加深理解,用时90分钟~