计算机科学与技术学院数据库系统概论第三章 关系数据库标准语言 SQL
(2)
3.3 查 询
3.3.1 概述
3.3.2 单表查询
3.3.3 连接查询
3.3.4 嵌套查询
3.3.5 集合查询
3.3.6 小结
3.3.3 连接查询同时涉及多个表的查询称为连接查询用来连接两个表的条件称为连接条件或连接谓词一般格式:
[<表名 1>.]<列名 1> <比较运算符 > [<表名 2>.]<列名 2>
比较运算符,=,>,<,>=,<=,!=
[<表名 1>.]<列名 1> BETWEEN [<表名 2>.]<列名 2>
AND [<表名 2>.]<列名 3>
连接查询 (续)
连接字段
连接谓词中的列名称为连接字段
连接条件中的各连接字段类型必须是可比的,
但不必是相同的连接操作的执行过程
嵌套循环法 (NESTED-LOOP)
首先在表 1中找到第一个元组,然后从头开始扫描表 2,
逐一查找满足连接件的元组,找到后就将表 1中的第一个元组与该元组拼接起来,形成结果表中一个元组 。
表 2全部查找完后,再找表 1中第二个元组,然后再从头开始扫描表 2,逐一查找满足连接条件的元组,找到后就将表 1中的第二个元组与该元组拼接起来,形成结果表中一个元组 。
重复上述操作,直到表 1中的全部元组都处理完毕排序合并法 (SORT-MERGE)
常用于 =连接
首先按连接属性对表 1和表 2排序
对表 1的第一个元组,从头开始扫描表 2,顺序查找满足连接条件的元组,找到后就将表 1中的第一个元组与该元组拼接起来,形成结果表中一个元组 。
当遇到表 2中第一条大于表 1连接字段值的元组时,
对表 2的查询不再继续排序合并法
找到表 1的第二条元组,然后从刚才的中断点处继续顺序扫描表 2,查找满足连接条件的元组,找到后就将表 1中的第一个元组与该元组拼接起来,形成结果表中一个元组 。 直接遇到表 2中大于表 1连接字段值的元组时,对表 2的查询不再继续
重复上述操作,直到表 1或表 2中的全部元组都处理完毕为止索引连接 (INDEX-JOIN)
对表 2按连接字段建立索引
对表 1中的每个元组,依次根据其连接字段值查询表 2的索引,从中找到满足条件的元组,找到后就将表 1中的第一个元组与该元组拼接起来,形成结果表中一个元组连接查询 (续)
SQL中连接查询的主要类型
广义笛卡尔积
等值连接 (含自然连接 )
非等值连接查询
自身连接查询
外连接查询
复合条件连接查询一、广义笛卡尔积
不带连接谓词的连接
很少使用例:
SELECT Student.*,SC.*
FROM Student,SC
二、等值与非等值连接查询等值连接,自然连接,非等值连接
[例 32] 查询每个学生及其选修课程的情况。
SELECT Student.*,SC.*
FROM Student,SC
WHERE Student.Sno = SC.Sno;
等值连接
连接运算符为 = 的连接操作
[<表名 1>.]<列名 1> = [<表名 2>.]<列名 2>
任何子句中引用表 1和表 2中同名属性时,都必须加表名前缀 。 引用唯一属性名时可以加也可以省略表名前缀 。
等值连接假设 Student表,SC表分别有下列数据:
Student表
Sno Sname Ssex Sage Sdept
95001 李勇 男 20 CS
95002 刘晨 女 19 IS
95003 王敏 女 18 MA
95004 张立 男 19 IS
等值连接
SC表
Sno Cno Grade
95001 1 92
95001 2 85
95001
95002
95002
3
2
3
88
90
80
自然连接
等值连接的一种特殊情况,把目标列中重复的属性列去掉 。
[例 33] 对 [例 32]用自然连接完成。
SELECT Student.Sno,Sname,Ssex,Sage,
Sdept,Cno,Grade
FROM Student,SC
WHERE Student.Sno = SC.Sno;
自然连接非等值连接查询连接运算符 不是 = 的连接操作
[<表名 1>.]<列名 1><比较运算符 >[<表名 2>.]<列名 2>
比较运算符,>,<,>=,<=,!=
[<表名 1>.]<列名 1> BETWEEN [<表名 2>.]<列名 2>
AND [<表名 2>.]<列名 3>
三、自身连接
一个表与其自己进行连接,称为表的 自身连接
需要给表起别名以示区别
由于所有属性名都是同名属性,因此必须使用别名前缀自身连接(续)
[例 34] 查询每一门课的间接先修课 ( 即先修课的先修课 )
SELECT FIRST.Cno,SECOND.Cpno
FROM Course FIRST,Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;
自身连接(续)
四、外连接( Outer Join)
外连接与普通连接的区别
普通连接操作只输出满足连接条件的元组
外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出外连接(续)
[例 33] 查询每个学生及其选修课程的情况包括没有选修课程的学生 ----用外连接操作
SELECT Student.Sno,Sname,Ssex,
Sage,Sdept,Cno,Grade
FROM Student,SC
WHERE Student.Sno = SC.Sno(*);
外连接(续)
结果:
Student.Sno Sname Ssex Sage Sdept Cno Grade
95001 李勇 男 20 CS 1 92
95001 李勇 男 20 CS 2 85
95001 李勇 男 20 CS 3 88
95002 刘晨 女 19 IS 2 90
95002 刘晨 女 19 IS 3 80
95003 王敏 女 18 MA
95004 张立 男 19 IS
外连接(续)
在表名后面加外连接操作符 (*)或 (+)指定非主体表
非主体表有一,万能,的虚行,该行全部由空值组成
虚行可以和主体表中所有不满足连接条件的元组进行连接
由于虚行各列全部是空值,因此与虚行连接的结果中,来自非主体表的属性值全部是空值外连接(续)
左外连接
外连接符出现在连接条件的左边
右外连接
外连接符出现在连接条件的右边五、复合条件连接
WHERE子句中含多个连接条件时,称为复合条件连接
[例 35]查询选修 2号课程且成绩在 90分以上的所有学生的学号、姓名
SELECT Student.Sno,student.Sname
FROM Student,SC
WHERE Student.Sno = SC.Sno AND
/* 连接谓词 */
SC.Cno= ' 2 ' AND /* 其他限定条件 */
SC.Grade > 90; /* 其他限定条件 */
五、复合条件连接多表连接
[例 36] 查询每个学生的学号,姓名,选修的课程名及成绩 。
SELECT Student.Sno,Sname,Cname,Grade
FROM Student,SC,Course
WHERE Student.Sno = SC.Sno
and SC.Cno = Course.Cno;
结果:
Student.Sno Sname Cname Grade
95001 李勇 数据库 92
95001 李勇 数学 85
95001 李勇 信息系统 88
95002 刘晨 数学 90
95002 刘晨 信息系统 80
多表连接
3.3 查 询
3.3.1 概述
3.3.2 单表查询
3.3.3 连接查询
3.3.4 嵌套查询
3.3.5 集合查询
3.3.6 小结
3.3.4 嵌套查询
嵌套查询概述
嵌套查询分类
嵌套查询求解方法
引出子查询的谓词嵌套查询 (续 )
嵌套查询概述
一个 SELECT-FROM-WHERE语句称为一个查询块
将一个查询块嵌套在另一个查询块的
WHERE子句或 HAVING短语的条件中的查询称为嵌套查询嵌套查询 (续 )
SELECT Sname 外层查询 /父查询
FROM Student
WHERE Sno IN
( SELECT Sno 内层查询 /子查询
FROM SC
WHERE Cno= ' 2 ');
嵌套查询 (续 )
子查询的限制
不能使用 ORDER BY子句
层层嵌套方式反映了 SQL语言的结构化
有些嵌套查询可以用连接运算替代嵌套查询分类
不相关子查询子查询的查询条件不依赖于父查询
相关子查询子查询的查询条件依赖于父查询嵌套查询求解方法
不相关子查询是由里向外逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。
嵌套查询求解方法(续)
相关子查询
首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若
WHERE子句返回值为真,则取此元组放入结果表;
然后再取外层表的下一个元组;
重复这一过程,直至外层表全部检查完为止。
引出子查询的谓词
带有 IN谓词的子查询
带有比较运算符的子查询
带有 ANY或 ALL谓词的子查询
带有 EXISTS谓词的子查询一、带有 IN谓词的子查询
[例 37] 查询与,刘晨,在同一个系学习的学生。
此查询要求可以分步来完成
① 确定,刘晨,所在系名
SELECT Sdept
FROM Student
WHERE Sname= ' 刘晨 ';
结果为:
Sdept
IS
带有 IN谓词的子查询(续)
② 查找所有在 IS系学习的学生。
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept= ' IS ';
结果为:
Sno Sname Sdept
95001 刘晨 IS
95004 张立 IS
构造嵌套查询将第一步查询嵌入到第二步查询的条件中
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN
(SELECT Sdept
FROM Student
WHERE Sname= ‘ 刘晨 ’ );
此查询为不相关子查询。 DBMS求解该查询时也是分步去做的。
构造嵌套查询带有 IN谓词的子查询(续)
用自身连接完成本查询要求
SELECT S1.Sno,S1.Sname,S1.Sdept
FROM Student S1,Student S2
WHERE S1.Sdept = S2.Sdept AND
S2.Sname = '刘晨 ';
带有 IN谓词的子查询(续)
父查询和子查询中的表均可以定义别名
SELECT Sno,Sname,Sdept
FROM Student S1
WHERE S1.Sdept IN
(SELECT Sdept
FROM Student S2
WHERE S2.Sname= ‘ 刘晨 ’ );
带有 IN谓词的子查询(续)
[例 38]查询选修了课程名为,信息系统,的学生学号和姓名
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= ‘信息系统 ’ ));
带有 IN谓词的子查询(续)
带有 IN谓词的子查询(续)
带有 IN谓词的子查询(续)
用连接查询
SELECT Sno,Sname
FROM Student,SC,Course
WHERE Student.Sno = SC.Sno AND
SC.Cno = Course.Cno AND
Course.Cname=‘信息系统 ’ ;
带有 IN谓词的子查询(续)
二、带有比较运算符的子查询
● 当能确切知道内层查询返回单值时,可用比较运算符( >,<,=,>=,
<=,!=或 < >)。
与 ANY或 ALL谓词配合使用带有比较运算符的子查询(续)
例:假设一个学生只可能在一个系学习,并且必须属于一个系,则在 [例 37]可以 用 = 代替 IN,
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept =
SELECT Sdept
FROM Student
WHERE Sname= ' 刘晨 ';
带有比较运算符的子查询(续)
带有比较运算符的子查询(续)
子查询一定要跟在比较符之后错误 的例子:
SELECT Sno,Sname,Sdept
FROM Student
WHERE ( SELECT Sdept
FROM Student
WHERE Sname= ‘ 刘晨 ’ )
= Sdept;
三、带有 ANY或 ALL谓词的子查询谓词语义
ANY:任意一个值
ALL:所有值带有 ANY或 ALL谓词的子查询(续)
需要配合使用比较运算符
> ANY 大于子查询结果中的某个值
> ALL 大于子查询结果中的所有值
< ANY 小于子查询结果中的某个值
< ALL 小于子查询结果中的所有值
>= ANY 大于等于子查询结果中的某个值
>= ALL 大于等于子查询结果中的所有值
<= ANY 小于等于子查询结果中的某个值
<= ALL 小于等于子查询结果中的所有值
= ANY 等于子查询结果中的某个值
=ALL 等于子查询结果中的所有值(通常没有实际意义)
!=(或 <>) ANY 不等于子查询结果中的某个值
!=(或 <>) ALL 不等于子查询结果中的任何一个值带有 ANY或 ALL谓词的子查询(续)
[例 39] 查询其他系中比信息系任意 一 个 (其中某一 个 )学生年龄小的学生姓名和年龄
SELECT Sname,Sage
FROM Student
WHERE Sage < ANY (SELECT Sage
FROM Student
WHERE Sdept= ' IS ')
AND Sdept <> ' IS ' ;
/* 注意这是父查询块中的条件 */
带有 ANY或 ALL谓词的子查询(续)
带有 ANY或 ALL谓词的子查询(续)
执行过程
1.DBMS执行此查询时,首先处理子查询,找出
IS系中所有学生的年龄,构成一个集合 (19,18)
2,处理父查询,找所有不是 IS系且年龄小于
19 或 18的学生带有 ANY或 ALL谓词的子查询(续)
● ANY和 ALL谓词有时可以用集函数实现
– ANY与 ALL与集函数的对应关系
= <>或 != < <= > >=
ANY IN -- <MAX <=MAX >MIN >= MIN
ALL -- NOT IN <MIN <= MIN >MAX >= MAX
带有 ANY或 ALL谓词的子查询(续)
– 用集函数实现子查询通常比直接用 ANY或
ALL查询效率要高,因为前者通常能够减少比较次数带有 ANY或 ALL谓词的子查询(续)
[例 39']:用集函数实现 [例 39]
SELECT Sname,Sage
FROM Student
WHERE Sage <
(SELECT MAX(Sage)
FROM Student
WHERE Sdept= ' IS ')
AND Sdept <> ' IS ’;
带有 ANY或 ALL谓词的子查询(续)
[例 40] 查询其他系中比信息系 所有 学生年龄 都小的学生姓名及年龄。
方法一:用 ALL谓词
SELECT Sname,Sage
FROM Student
WHERE Sage < ALL
(SELECT Sage
FROM Student
WHERE Sdept= ' IS ')
AND Sdept <> ' IS ’;
查询结果为空表。
带有 ANY或 ALL谓词的子查询(续)
方法二:用集函数
SELECT Sname,Sage
FROM Student
WHERE Sage <
(SELECT MIN(Sage)
FROM Student
WHERE Sdept= ' IS ')
AND Sdept <>' IS ’;
四、带有 EXISTS谓词的子查询
1,EXISTS谓词
2,NOT EXISTS谓词
3,不同形式的查询间的替换
4,相关子查询的效率
5,用 EXISTS/NOT EXISTS实现全称量词
6,用 EXISTS/NOT EXISTS实现逻辑蕴函带有 EXISTS谓词的子查询 (续)
● 1,EXISTS谓词
– 存在量词?
– 带有 EXISTS谓词的子查询不返回任何数据,只产生逻辑真值,true”或逻辑假值,false”。
● 若内层查询结果非空,则返回真值
● 若内层查询结果为空,则返回假值
– 由 EXISTS引出的子查询,其目标列表达式通常都用
*,因为带 EXISTS的子查询只返回真值或假值,给出列名无实际意义
● 2,NOT EXISTS谓词带有 EXISTS谓词的子查询 (续)
[例 41] 查询所有选修了 1号课程的学生姓名。
– 用嵌套查询
SELECT Sname
FROM Student
WHERE EXISTS
(SELECT *
FROM SC /*相关子查询 */
WHERE Sno=Student.Sno AND
Cno= ' 1 ');
求解过程带有 EXISTS谓词的子查询 (续)
思路分析:
● 本查询涉及 Student和 SC关系。
● 在 Student中依次取每个元组的 Sno值,用此值去检查 SC关系。
● 若 SC中存在这样的元组,其 Sno值等于此
Student.Sno值,并且其 Cno= '1',则取此
Student.Sname送入结果关系。
带有 EXISTS谓词的子查询 (续)
用连接运算
SELECT Sname
FROM Student,SC
WHERE Student.Sno=SC.Sno AND
SC.Cno= '1';
带有 EXISTS谓词的子查询 (续)
[例 42] 查询没有选修 1号课程的学生姓名 。
SELECT Sname
FROM Student
WHERE NOT EXISTS
(SELECT *
FROM SC
WHERE Sno = Student.Sno
AND Cno='1');
此例用连接运算难于实现带有 EXISTS谓词的子查询 (续)
3,不同形式的查询间的替换一些 带 EXISTS或 NOT EXISTS谓词的子查询不能被其他形式的子查询等价替换所有 带 IN谓词、比较运算符,ANY和 ALL谓词的子查询都能用带 EXISTS谓词的子查询等价替换。
带有 EXISTS谓词的子查询 (续)
例,[例 37]查询与,刘晨,在同一个系学习的学生。 可以用带 EXISTS谓词的子查询替换:
SELECT Sno,Sname,Sdept
FROM Student S1
WHERE EXISTS
SELECT *
FROM Student S2
WHERE S2.Sdept = S1.Sdept AND
S2.Sname = ' 刘晨 ';
带有 EXISTS谓词的子查询 (续)
5.用 EXISTS/NOT EXISTS实现全称量词 (难点 )
SQL语言中没有全称量词? ( For all)
可以把带有全称量词的谓词转换为等价的带有存在量词的谓词:
(?x)P ≡? (? x(? P))
带有 EXISTS谓词的子查询 (续)
[例 43] 查询选修了全部课程的学生姓名 。
SELECT Sname
FROM Student
WHERE NOT EXISTS
( SELECT *
FROM Course
WHERE NOT EXISTS
(SELECT *
FROM SC
WHERE Sno= Student.Sno
AND Cno= Course.Cno) ;
带有 EXISTS谓词的子查询 (续)
6,用 EXISTS/NOT EXISTS实现逻辑蕴函 (难点 )
SQL语言中没有蕴函 (Implication)逻辑运算
可以利用谓词演算将逻辑蕴函谓词等价转换为:
p? q ≡? p∨ q
带有 EXISTS谓词的子查询 (续)
[例 44] 查询至少选修了学生 95002选修的全部课程的学生号码。
解题思路:
● 用逻辑蕴函表达:查询学号为 x的学生,对所有的课程
y,只要 95002学生选修了课程 y,则 x也选修了 y。
● 形式化表示:
用 P表示谓词,学生 95002选修了课程 y”
用 q表示谓词,学生 x选修了课程 y”
则上述查询为,(?y) p? q
带有 EXISTS谓词的子查询 (续)
● 等价变换:
(?y)p? q ≡? (?y (?(p? q ))
≡? (?y (?(? p∨ q)
≡y(p∧?q)
● 变换后语义:不存在这样的课程 y,学生 95002
选修了 y,而学生 x没有选。
带有 EXISTS谓词的子查询 (续)
● 用 NOT EXISTS谓词表示,
SELECT DISTINCT Sno
FROM SC SCX
WHERE NOT EXISTS
(SELECT *
FROM SC SCY
WHERE SCY.Sno = ' 95002 ' AND
NOT EXISTS
(SELECT *
FROM SC SCZ
WHERE SCZ.Sno=SCX.Sno AND
SCZ.Cno=SCY.Cno));
3.3 查 询
3.3.1 概述
3.3.2 单表查询
3.3.3 连接查询
3.3.4 嵌套查询
3.3.5 集合查询
3.3.6 小结
3.3.5 集合查询标准 SQL直接支持的集合操作种类并操作 (UNION)
一般商用数据库支持的集合操作种类并操作 (UNION)
交操作 (INTERSECT)
差操作 (MINUS)
1,并操作
形式
<查询块 >
UNION
<查询块 >
参加 UNION操作的各结果表的列数必须相同;
对应项的数据类型也必须相同并操作(续)
[例 45] 查询计算机科学系的学生及年龄不大于
19岁的学生。
方法一:
SELECT *
FROM Student
WHERE Sdept= 'CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19;
并操作(续)
方法二:
SELECT DISTINCT *
FROM Student
WHERE Sdept= 'CS' OR Sage<=19;
并操作(续)
[例 46] 查询选修了课程 1或者选修了课程 2的学生。
方法一:
SELECT Sno
FROM SC
WHERE Cno=' 1 '
UNION
SELECT Sno
FROM SC
WHERE Cno= ' 2 ';
并操作(续)
方法二:
SELECT DISTINCT Sno
FROM SC
WHERE Cno=' 1 ' OR Cno= ' 2 ';
并操作(续)
[例 47] 设数据库中有一教师表 Teacher(Tno,
Tname,...)。查询学校中所有师生的姓名。
SELECT Sname
FROM Student
UNION
SELECT Tname
FROM Teacher;
2,交操作标准 SQL中没有提供集合交操作,但可用其他方法间接实现。
2,交操作
[例 48] 查询计算机科学系的学生与年龄不大于
19岁的学生的交集本例实际上就是查询计算机科学系中年龄不大于
19岁的学生
SELECT *
FROM Student
WHERE Sdept= 'CS' AND
Sage<=19;
交操作(续)
[例 49] 查询选修课程 1的学生集合与选修课程 2
的学生集合的交集本例实际上是查询既选修了课程 1又选修了课程 2
的学生
SELECT Sno
FROM SC
WHERE Cno=' 1 ' AND Sno IN
(SELECT Sno
FROM SC
WHERE Cno=' 2 ');
交操作(续)
[例 50] 查询学生姓名与教师姓名的交集本例实际上是查询学校中与教师同名的学生姓名
SELECT DISTINCT Sname
FROM Student
WHERE Sname IN
(SELECT Tname
FROM Teacher);
3,差操作标准 SQL中没有提供集合差操作,但可用其他方法间接实现。
3,差操作
[例 51] 查询计算机科学系的学生与年龄不大于
19岁的学生的差集。
本例实际上是查询计算机科学系中年龄大于 19
岁的学生
SELECT *
FROM Student
WHERE Sdept= 'CS' AND
Sage>19;
差操作(续)
[例 52] 查询学生姓名与教师姓名的差集本例实际上是查询学校中未与教师同名的学生姓名
SELECT DISTINCT Sname
FROM Student
WHERE Sname NOT IN
(SELECT Tname
FROM Teacher);
4,对集合操作结果的排序
ORDER BY子句只能用于对最终查询结果排序,不能对中间结果排序
任何情况下,ORDER BY子句只能出现在最后
对集合操作结果排序时,ORDER BY子句中用数字指定排序属性对集合操作结果的排序(续)
[例 53] 错误写法
SELECT *
FROM Student
WHERE Sdept= 'CS'
ORDER BY Sno
UNION
SELECT *
FROM Student
WHERE Sage<=19
ORDER BY Sno;
对集合操作结果的排序(续)
正确写法
SELECT *
FROM Student
WHERE Sdept= 'CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19
ORDER BY 1;
3.3.6 SELECT语句的一般格式
SELECT [ALL|DISTINCT]
<目标列表达式 > [别名 ] [,<目标列表达式 > [别名 ]] …
FROM <表名或视图名 > [别名 ]
[,<表名或视图名 > [别名 ]] …
[WHERE <条件表达式 >]
[GROUP BY <列名 1>[,<列名 1’>],..
[HAVING <条件表达式 >]]
[ORDER BY <列名 2> [ASC|DESC]
[,<列名 2’> [ASC|DESC] ] … ];
目标列表达式
目标列表达式格式
(1) [ <表名 >.] *
(2) [<表名 >.]<属性列名表达式 >[,[<表名 >.]<属性列名表达式 >] …
<属性列名表达式 >:由 属性列,作用于属性列的 集函数 和 常量 的任意算术运算( +,-,*,/)组成的运算公式。
集函数格式
COUNT
SUM
AVG ([DISTINCT|ALL] <列名 >)
MAX
MIN
COUNT ([DISTINCT|ALL] *)
条件表达式格式
( 1)
<属性列名 >
<属性列名 > θ <常量 >
[ANY|ALL] (SELECT语句 )
条件表达式格式
( 2)
<属性列名 > <属性列名 >
<属性列名 > [NOT] BETWEEN <常量 > AND <常量 >
(SELECT (SELECT
语句 ) 语句 )
条件表达式格式
( 3) (<值 1>[,<值 2> ] … )
<属性列名 > [NOT] IN
(SELECT语句 )
条件表达式格式
(4) <属性列名 > [NOT] LIKE <匹配串 >
(5) <属性列名 > IS [NOT] NULL
(6) [NOT] EXISTS (SELECT语句 )
条件表达式格式
( 7) AND AND
<条件表达式 > <条件表达式 > <条件表达
> …
OR OR
(2)
3.3 查 询
3.3.1 概述
3.3.2 单表查询
3.3.3 连接查询
3.3.4 嵌套查询
3.3.5 集合查询
3.3.6 小结
3.3.3 连接查询同时涉及多个表的查询称为连接查询用来连接两个表的条件称为连接条件或连接谓词一般格式:
[<表名 1>.]<列名 1> <比较运算符 > [<表名 2>.]<列名 2>
比较运算符,=,>,<,>=,<=,!=
[<表名 1>.]<列名 1> BETWEEN [<表名 2>.]<列名 2>
AND [<表名 2>.]<列名 3>
连接查询 (续)
连接字段
连接谓词中的列名称为连接字段
连接条件中的各连接字段类型必须是可比的,
但不必是相同的连接操作的执行过程
嵌套循环法 (NESTED-LOOP)
首先在表 1中找到第一个元组,然后从头开始扫描表 2,
逐一查找满足连接件的元组,找到后就将表 1中的第一个元组与该元组拼接起来,形成结果表中一个元组 。
表 2全部查找完后,再找表 1中第二个元组,然后再从头开始扫描表 2,逐一查找满足连接条件的元组,找到后就将表 1中的第二个元组与该元组拼接起来,形成结果表中一个元组 。
重复上述操作,直到表 1中的全部元组都处理完毕排序合并法 (SORT-MERGE)
常用于 =连接
首先按连接属性对表 1和表 2排序
对表 1的第一个元组,从头开始扫描表 2,顺序查找满足连接条件的元组,找到后就将表 1中的第一个元组与该元组拼接起来,形成结果表中一个元组 。
当遇到表 2中第一条大于表 1连接字段值的元组时,
对表 2的查询不再继续排序合并法
找到表 1的第二条元组,然后从刚才的中断点处继续顺序扫描表 2,查找满足连接条件的元组,找到后就将表 1中的第一个元组与该元组拼接起来,形成结果表中一个元组 。 直接遇到表 2中大于表 1连接字段值的元组时,对表 2的查询不再继续
重复上述操作,直到表 1或表 2中的全部元组都处理完毕为止索引连接 (INDEX-JOIN)
对表 2按连接字段建立索引
对表 1中的每个元组,依次根据其连接字段值查询表 2的索引,从中找到满足条件的元组,找到后就将表 1中的第一个元组与该元组拼接起来,形成结果表中一个元组连接查询 (续)
SQL中连接查询的主要类型
广义笛卡尔积
等值连接 (含自然连接 )
非等值连接查询
自身连接查询
外连接查询
复合条件连接查询一、广义笛卡尔积
不带连接谓词的连接
很少使用例:
SELECT Student.*,SC.*
FROM Student,SC
二、等值与非等值连接查询等值连接,自然连接,非等值连接
[例 32] 查询每个学生及其选修课程的情况。
SELECT Student.*,SC.*
FROM Student,SC
WHERE Student.Sno = SC.Sno;
等值连接
连接运算符为 = 的连接操作
[<表名 1>.]<列名 1> = [<表名 2>.]<列名 2>
任何子句中引用表 1和表 2中同名属性时,都必须加表名前缀 。 引用唯一属性名时可以加也可以省略表名前缀 。
等值连接假设 Student表,SC表分别有下列数据:
Student表
Sno Sname Ssex Sage Sdept
95001 李勇 男 20 CS
95002 刘晨 女 19 IS
95003 王敏 女 18 MA
95004 张立 男 19 IS
等值连接
SC表
Sno Cno Grade
95001 1 92
95001 2 85
95001
95002
95002
3
2
3
88
90
80
自然连接
等值连接的一种特殊情况,把目标列中重复的属性列去掉 。
[例 33] 对 [例 32]用自然连接完成。
SELECT Student.Sno,Sname,Ssex,Sage,
Sdept,Cno,Grade
FROM Student,SC
WHERE Student.Sno = SC.Sno;
自然连接非等值连接查询连接运算符 不是 = 的连接操作
[<表名 1>.]<列名 1><比较运算符 >[<表名 2>.]<列名 2>
比较运算符,>,<,>=,<=,!=
[<表名 1>.]<列名 1> BETWEEN [<表名 2>.]<列名 2>
AND [<表名 2>.]<列名 3>
三、自身连接
一个表与其自己进行连接,称为表的 自身连接
需要给表起别名以示区别
由于所有属性名都是同名属性,因此必须使用别名前缀自身连接(续)
[例 34] 查询每一门课的间接先修课 ( 即先修课的先修课 )
SELECT FIRST.Cno,SECOND.Cpno
FROM Course FIRST,Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;
自身连接(续)
四、外连接( Outer Join)
外连接与普通连接的区别
普通连接操作只输出满足连接条件的元组
外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出外连接(续)
[例 33] 查询每个学生及其选修课程的情况包括没有选修课程的学生 ----用外连接操作
SELECT Student.Sno,Sname,Ssex,
Sage,Sdept,Cno,Grade
FROM Student,SC
WHERE Student.Sno = SC.Sno(*);
外连接(续)
结果:
Student.Sno Sname Ssex Sage Sdept Cno Grade
95001 李勇 男 20 CS 1 92
95001 李勇 男 20 CS 2 85
95001 李勇 男 20 CS 3 88
95002 刘晨 女 19 IS 2 90
95002 刘晨 女 19 IS 3 80
95003 王敏 女 18 MA
95004 张立 男 19 IS
外连接(续)
在表名后面加外连接操作符 (*)或 (+)指定非主体表
非主体表有一,万能,的虚行,该行全部由空值组成
虚行可以和主体表中所有不满足连接条件的元组进行连接
由于虚行各列全部是空值,因此与虚行连接的结果中,来自非主体表的属性值全部是空值外连接(续)
左外连接
外连接符出现在连接条件的左边
右外连接
外连接符出现在连接条件的右边五、复合条件连接
WHERE子句中含多个连接条件时,称为复合条件连接
[例 35]查询选修 2号课程且成绩在 90分以上的所有学生的学号、姓名
SELECT Student.Sno,student.Sname
FROM Student,SC
WHERE Student.Sno = SC.Sno AND
/* 连接谓词 */
SC.Cno= ' 2 ' AND /* 其他限定条件 */
SC.Grade > 90; /* 其他限定条件 */
五、复合条件连接多表连接
[例 36] 查询每个学生的学号,姓名,选修的课程名及成绩 。
SELECT Student.Sno,Sname,Cname,Grade
FROM Student,SC,Course
WHERE Student.Sno = SC.Sno
and SC.Cno = Course.Cno;
结果:
Student.Sno Sname Cname Grade
95001 李勇 数据库 92
95001 李勇 数学 85
95001 李勇 信息系统 88
95002 刘晨 数学 90
95002 刘晨 信息系统 80
多表连接
3.3 查 询
3.3.1 概述
3.3.2 单表查询
3.3.3 连接查询
3.3.4 嵌套查询
3.3.5 集合查询
3.3.6 小结
3.3.4 嵌套查询
嵌套查询概述
嵌套查询分类
嵌套查询求解方法
引出子查询的谓词嵌套查询 (续 )
嵌套查询概述
一个 SELECT-FROM-WHERE语句称为一个查询块
将一个查询块嵌套在另一个查询块的
WHERE子句或 HAVING短语的条件中的查询称为嵌套查询嵌套查询 (续 )
SELECT Sname 外层查询 /父查询
FROM Student
WHERE Sno IN
( SELECT Sno 内层查询 /子查询
FROM SC
WHERE Cno= ' 2 ');
嵌套查询 (续 )
子查询的限制
不能使用 ORDER BY子句
层层嵌套方式反映了 SQL语言的结构化
有些嵌套查询可以用连接运算替代嵌套查询分类
不相关子查询子查询的查询条件不依赖于父查询
相关子查询子查询的查询条件依赖于父查询嵌套查询求解方法
不相关子查询是由里向外逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。
嵌套查询求解方法(续)
相关子查询
首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若
WHERE子句返回值为真,则取此元组放入结果表;
然后再取外层表的下一个元组;
重复这一过程,直至外层表全部检查完为止。
引出子查询的谓词
带有 IN谓词的子查询
带有比较运算符的子查询
带有 ANY或 ALL谓词的子查询
带有 EXISTS谓词的子查询一、带有 IN谓词的子查询
[例 37] 查询与,刘晨,在同一个系学习的学生。
此查询要求可以分步来完成
① 确定,刘晨,所在系名
SELECT Sdept
FROM Student
WHERE Sname= ' 刘晨 ';
结果为:
Sdept
IS
带有 IN谓词的子查询(续)
② 查找所有在 IS系学习的学生。
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept= ' IS ';
结果为:
Sno Sname Sdept
95001 刘晨 IS
95004 张立 IS
构造嵌套查询将第一步查询嵌入到第二步查询的条件中
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN
(SELECT Sdept
FROM Student
WHERE Sname= ‘ 刘晨 ’ );
此查询为不相关子查询。 DBMS求解该查询时也是分步去做的。
构造嵌套查询带有 IN谓词的子查询(续)
用自身连接完成本查询要求
SELECT S1.Sno,S1.Sname,S1.Sdept
FROM Student S1,Student S2
WHERE S1.Sdept = S2.Sdept AND
S2.Sname = '刘晨 ';
带有 IN谓词的子查询(续)
父查询和子查询中的表均可以定义别名
SELECT Sno,Sname,Sdept
FROM Student S1
WHERE S1.Sdept IN
(SELECT Sdept
FROM Student S2
WHERE S2.Sname= ‘ 刘晨 ’ );
带有 IN谓词的子查询(续)
[例 38]查询选修了课程名为,信息系统,的学生学号和姓名
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= ‘信息系统 ’ ));
带有 IN谓词的子查询(续)
带有 IN谓词的子查询(续)
带有 IN谓词的子查询(续)
用连接查询
SELECT Sno,Sname
FROM Student,SC,Course
WHERE Student.Sno = SC.Sno AND
SC.Cno = Course.Cno AND
Course.Cname=‘信息系统 ’ ;
带有 IN谓词的子查询(续)
二、带有比较运算符的子查询
● 当能确切知道内层查询返回单值时,可用比较运算符( >,<,=,>=,
<=,!=或 < >)。
与 ANY或 ALL谓词配合使用带有比较运算符的子查询(续)
例:假设一个学生只可能在一个系学习,并且必须属于一个系,则在 [例 37]可以 用 = 代替 IN,
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept =
SELECT Sdept
FROM Student
WHERE Sname= ' 刘晨 ';
带有比较运算符的子查询(续)
带有比较运算符的子查询(续)
子查询一定要跟在比较符之后错误 的例子:
SELECT Sno,Sname,Sdept
FROM Student
WHERE ( SELECT Sdept
FROM Student
WHERE Sname= ‘ 刘晨 ’ )
= Sdept;
三、带有 ANY或 ALL谓词的子查询谓词语义
ANY:任意一个值
ALL:所有值带有 ANY或 ALL谓词的子查询(续)
需要配合使用比较运算符
> ANY 大于子查询结果中的某个值
> ALL 大于子查询结果中的所有值
< ANY 小于子查询结果中的某个值
< ALL 小于子查询结果中的所有值
>= ANY 大于等于子查询结果中的某个值
>= ALL 大于等于子查询结果中的所有值
<= ANY 小于等于子查询结果中的某个值
<= ALL 小于等于子查询结果中的所有值
= ANY 等于子查询结果中的某个值
=ALL 等于子查询结果中的所有值(通常没有实际意义)
!=(或 <>) ANY 不等于子查询结果中的某个值
!=(或 <>) ALL 不等于子查询结果中的任何一个值带有 ANY或 ALL谓词的子查询(续)
[例 39] 查询其他系中比信息系任意 一 个 (其中某一 个 )学生年龄小的学生姓名和年龄
SELECT Sname,Sage
FROM Student
WHERE Sage < ANY (SELECT Sage
FROM Student
WHERE Sdept= ' IS ')
AND Sdept <> ' IS ' ;
/* 注意这是父查询块中的条件 */
带有 ANY或 ALL谓词的子查询(续)
带有 ANY或 ALL谓词的子查询(续)
执行过程
1.DBMS执行此查询时,首先处理子查询,找出
IS系中所有学生的年龄,构成一个集合 (19,18)
2,处理父查询,找所有不是 IS系且年龄小于
19 或 18的学生带有 ANY或 ALL谓词的子查询(续)
● ANY和 ALL谓词有时可以用集函数实现
– ANY与 ALL与集函数的对应关系
= <>或 != < <= > >=
ANY IN -- <MAX <=MAX >MIN >= MIN
ALL -- NOT IN <MIN <= MIN >MAX >= MAX
带有 ANY或 ALL谓词的子查询(续)
– 用集函数实现子查询通常比直接用 ANY或
ALL查询效率要高,因为前者通常能够减少比较次数带有 ANY或 ALL谓词的子查询(续)
[例 39']:用集函数实现 [例 39]
SELECT Sname,Sage
FROM Student
WHERE Sage <
(SELECT MAX(Sage)
FROM Student
WHERE Sdept= ' IS ')
AND Sdept <> ' IS ’;
带有 ANY或 ALL谓词的子查询(续)
[例 40] 查询其他系中比信息系 所有 学生年龄 都小的学生姓名及年龄。
方法一:用 ALL谓词
SELECT Sname,Sage
FROM Student
WHERE Sage < ALL
(SELECT Sage
FROM Student
WHERE Sdept= ' IS ')
AND Sdept <> ' IS ’;
查询结果为空表。
带有 ANY或 ALL谓词的子查询(续)
方法二:用集函数
SELECT Sname,Sage
FROM Student
WHERE Sage <
(SELECT MIN(Sage)
FROM Student
WHERE Sdept= ' IS ')
AND Sdept <>' IS ’;
四、带有 EXISTS谓词的子查询
1,EXISTS谓词
2,NOT EXISTS谓词
3,不同形式的查询间的替换
4,相关子查询的效率
5,用 EXISTS/NOT EXISTS实现全称量词
6,用 EXISTS/NOT EXISTS实现逻辑蕴函带有 EXISTS谓词的子查询 (续)
● 1,EXISTS谓词
– 存在量词?
– 带有 EXISTS谓词的子查询不返回任何数据,只产生逻辑真值,true”或逻辑假值,false”。
● 若内层查询结果非空,则返回真值
● 若内层查询结果为空,则返回假值
– 由 EXISTS引出的子查询,其目标列表达式通常都用
*,因为带 EXISTS的子查询只返回真值或假值,给出列名无实际意义
● 2,NOT EXISTS谓词带有 EXISTS谓词的子查询 (续)
[例 41] 查询所有选修了 1号课程的学生姓名。
– 用嵌套查询
SELECT Sname
FROM Student
WHERE EXISTS
(SELECT *
FROM SC /*相关子查询 */
WHERE Sno=Student.Sno AND
Cno= ' 1 ');
求解过程带有 EXISTS谓词的子查询 (续)
思路分析:
● 本查询涉及 Student和 SC关系。
● 在 Student中依次取每个元组的 Sno值,用此值去检查 SC关系。
● 若 SC中存在这样的元组,其 Sno值等于此
Student.Sno值,并且其 Cno= '1',则取此
Student.Sname送入结果关系。
带有 EXISTS谓词的子查询 (续)
用连接运算
SELECT Sname
FROM Student,SC
WHERE Student.Sno=SC.Sno AND
SC.Cno= '1';
带有 EXISTS谓词的子查询 (续)
[例 42] 查询没有选修 1号课程的学生姓名 。
SELECT Sname
FROM Student
WHERE NOT EXISTS
(SELECT *
FROM SC
WHERE Sno = Student.Sno
AND Cno='1');
此例用连接运算难于实现带有 EXISTS谓词的子查询 (续)
3,不同形式的查询间的替换一些 带 EXISTS或 NOT EXISTS谓词的子查询不能被其他形式的子查询等价替换所有 带 IN谓词、比较运算符,ANY和 ALL谓词的子查询都能用带 EXISTS谓词的子查询等价替换。
带有 EXISTS谓词的子查询 (续)
例,[例 37]查询与,刘晨,在同一个系学习的学生。 可以用带 EXISTS谓词的子查询替换:
SELECT Sno,Sname,Sdept
FROM Student S1
WHERE EXISTS
SELECT *
FROM Student S2
WHERE S2.Sdept = S1.Sdept AND
S2.Sname = ' 刘晨 ';
带有 EXISTS谓词的子查询 (续)
5.用 EXISTS/NOT EXISTS实现全称量词 (难点 )
SQL语言中没有全称量词? ( For all)
可以把带有全称量词的谓词转换为等价的带有存在量词的谓词:
(?x)P ≡? (? x(? P))
带有 EXISTS谓词的子查询 (续)
[例 43] 查询选修了全部课程的学生姓名 。
SELECT Sname
FROM Student
WHERE NOT EXISTS
( SELECT *
FROM Course
WHERE NOT EXISTS
(SELECT *
FROM SC
WHERE Sno= Student.Sno
AND Cno= Course.Cno) ;
带有 EXISTS谓词的子查询 (续)
6,用 EXISTS/NOT EXISTS实现逻辑蕴函 (难点 )
SQL语言中没有蕴函 (Implication)逻辑运算
可以利用谓词演算将逻辑蕴函谓词等价转换为:
p? q ≡? p∨ q
带有 EXISTS谓词的子查询 (续)
[例 44] 查询至少选修了学生 95002选修的全部课程的学生号码。
解题思路:
● 用逻辑蕴函表达:查询学号为 x的学生,对所有的课程
y,只要 95002学生选修了课程 y,则 x也选修了 y。
● 形式化表示:
用 P表示谓词,学生 95002选修了课程 y”
用 q表示谓词,学生 x选修了课程 y”
则上述查询为,(?y) p? q
带有 EXISTS谓词的子查询 (续)
● 等价变换:
(?y)p? q ≡? (?y (?(p? q ))
≡? (?y (?(? p∨ q)
≡y(p∧?q)
● 变换后语义:不存在这样的课程 y,学生 95002
选修了 y,而学生 x没有选。
带有 EXISTS谓词的子查询 (续)
● 用 NOT EXISTS谓词表示,
SELECT DISTINCT Sno
FROM SC SCX
WHERE NOT EXISTS
(SELECT *
FROM SC SCY
WHERE SCY.Sno = ' 95002 ' AND
NOT EXISTS
(SELECT *
FROM SC SCZ
WHERE SCZ.Sno=SCX.Sno AND
SCZ.Cno=SCY.Cno));
3.3 查 询
3.3.1 概述
3.3.2 单表查询
3.3.3 连接查询
3.3.4 嵌套查询
3.3.5 集合查询
3.3.6 小结
3.3.5 集合查询标准 SQL直接支持的集合操作种类并操作 (UNION)
一般商用数据库支持的集合操作种类并操作 (UNION)
交操作 (INTERSECT)
差操作 (MINUS)
1,并操作
形式
<查询块 >
UNION
<查询块 >
参加 UNION操作的各结果表的列数必须相同;
对应项的数据类型也必须相同并操作(续)
[例 45] 查询计算机科学系的学生及年龄不大于
19岁的学生。
方法一:
SELECT *
FROM Student
WHERE Sdept= 'CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19;
并操作(续)
方法二:
SELECT DISTINCT *
FROM Student
WHERE Sdept= 'CS' OR Sage<=19;
并操作(续)
[例 46] 查询选修了课程 1或者选修了课程 2的学生。
方法一:
SELECT Sno
FROM SC
WHERE Cno=' 1 '
UNION
SELECT Sno
FROM SC
WHERE Cno= ' 2 ';
并操作(续)
方法二:
SELECT DISTINCT Sno
FROM SC
WHERE Cno=' 1 ' OR Cno= ' 2 ';
并操作(续)
[例 47] 设数据库中有一教师表 Teacher(Tno,
Tname,...)。查询学校中所有师生的姓名。
SELECT Sname
FROM Student
UNION
SELECT Tname
FROM Teacher;
2,交操作标准 SQL中没有提供集合交操作,但可用其他方法间接实现。
2,交操作
[例 48] 查询计算机科学系的学生与年龄不大于
19岁的学生的交集本例实际上就是查询计算机科学系中年龄不大于
19岁的学生
SELECT *
FROM Student
WHERE Sdept= 'CS' AND
Sage<=19;
交操作(续)
[例 49] 查询选修课程 1的学生集合与选修课程 2
的学生集合的交集本例实际上是查询既选修了课程 1又选修了课程 2
的学生
SELECT Sno
FROM SC
WHERE Cno=' 1 ' AND Sno IN
(SELECT Sno
FROM SC
WHERE Cno=' 2 ');
交操作(续)
[例 50] 查询学生姓名与教师姓名的交集本例实际上是查询学校中与教师同名的学生姓名
SELECT DISTINCT Sname
FROM Student
WHERE Sname IN
(SELECT Tname
FROM Teacher);
3,差操作标准 SQL中没有提供集合差操作,但可用其他方法间接实现。
3,差操作
[例 51] 查询计算机科学系的学生与年龄不大于
19岁的学生的差集。
本例实际上是查询计算机科学系中年龄大于 19
岁的学生
SELECT *
FROM Student
WHERE Sdept= 'CS' AND
Sage>19;
差操作(续)
[例 52] 查询学生姓名与教师姓名的差集本例实际上是查询学校中未与教师同名的学生姓名
SELECT DISTINCT Sname
FROM Student
WHERE Sname NOT IN
(SELECT Tname
FROM Teacher);
4,对集合操作结果的排序
ORDER BY子句只能用于对最终查询结果排序,不能对中间结果排序
任何情况下,ORDER BY子句只能出现在最后
对集合操作结果排序时,ORDER BY子句中用数字指定排序属性对集合操作结果的排序(续)
[例 53] 错误写法
SELECT *
FROM Student
WHERE Sdept= 'CS'
ORDER BY Sno
UNION
SELECT *
FROM Student
WHERE Sage<=19
ORDER BY Sno;
对集合操作结果的排序(续)
正确写法
SELECT *
FROM Student
WHERE Sdept= 'CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19
ORDER BY 1;
3.3.6 SELECT语句的一般格式
SELECT [ALL|DISTINCT]
<目标列表达式 > [别名 ] [,<目标列表达式 > [别名 ]] …
FROM <表名或视图名 > [别名 ]
[,<表名或视图名 > [别名 ]] …
[WHERE <条件表达式 >]
[GROUP BY <列名 1>[,<列名 1’>],..
[HAVING <条件表达式 >]]
[ORDER BY <列名 2> [ASC|DESC]
[,<列名 2’> [ASC|DESC] ] … ];
目标列表达式
目标列表达式格式
(1) [ <表名 >.] *
(2) [<表名 >.]<属性列名表达式 >[,[<表名 >.]<属性列名表达式 >] …
<属性列名表达式 >:由 属性列,作用于属性列的 集函数 和 常量 的任意算术运算( +,-,*,/)组成的运算公式。
集函数格式
COUNT
SUM
AVG ([DISTINCT|ALL] <列名 >)
MAX
MIN
COUNT ([DISTINCT|ALL] *)
条件表达式格式
( 1)
<属性列名 >
<属性列名 > θ <常量 >
[ANY|ALL] (SELECT语句 )
条件表达式格式
( 2)
<属性列名 > <属性列名 >
<属性列名 > [NOT] BETWEEN <常量 > AND <常量 >
(SELECT (SELECT
语句 ) 语句 )
条件表达式格式
( 3) (<值 1>[,<值 2> ] … )
<属性列名 > [NOT] IN
(SELECT语句 )
条件表达式格式
(4) <属性列名 > [NOT] LIKE <匹配串 >
(5) <属性列名 > IS [NOT] NULL
(6) [NOT] EXISTS (SELECT语句 )
条件表达式格式
( 7) AND AND
<条件表达式 > <条件表达式 > <条件表达
> …
OR OR