教材为数据库系统概论第五版(王珊)
最重量级的一章。从后续的学习,基本所有实验,大作业和考试都会涉及SQL,SQL实际上是有很多变化的,书上讲的只是最基本的(做了大作业才知道SQL能有这么多变化)。最重要的当属数据查询这部分。当然增删改也要会。还要注意drop和alter和delete这些作用的对象是什么,都有很多坑。学会这章最好的办法就是做实验,然后一条一条SQL手动打然后运行。本书的前6个实验我已上传到博客上了,可以点我主页查看。
3.1 SQL概述
SQL(Structured Query Language):结构化查询语言,是关系数据库的标准语言,SQL是一个通用的、功能极强的关系数据库语言。
3.1.1 SQL的产生与发展
3.1.2 SQL的特点
-
综合统一
-
高度非过程化
-
面向集合的操作方式
-
以同一种语法结构提供多种使用方式
-
语言简捷,易学易用
SQL功能极强,完成核心功能只用了9个动词
3.1.3 SQL的基本概念
SQL支持关系数据库三级模式结构。
3.2 学生-课程数据库
学生表: S t u d e n t ( S n o , S n a m e , S s e x , S a g e , S d e p t ) 学生表:Student(S_{no},S_{name},S_{sex},S_{age},S_{dept}) 学生表:Student(Sno,Sname,Ssex,Sage,Sdept)
课程表:
C
o
u
r
s
e
(
C
n
o
,
C
n
a
m
e
,
C
p
n
o
,
C
c
r
e
d
i
t
)
课程表:Course(C_{no},C_{name},C_{pno},C_{credit})
课程表:Course(Cno,Cname,Cpno,Ccredit)
学生选课表:
S
C
(
S
n
o
,
C
n
o
,
G
r
a
d
e
)
学生选课表:SC(S_{no},C_{no},Grade)
学生选课表:SC(Sno,Cno,Grade)
3.3 数据定义
SQL的数据定义功能: 模式定义、表定义、视图和索引的定义
3.3.1 模式的定义与删除
- 定义模式(一般不考)
语句格式如下:
CREATE SCHEMA <模式名> AUTHORIZATION <用户名>;
[例1] 定义一个学生-课程模式S-T
CREATE SCHEMA “S-T” AUTHORIZATION WANG;
为用户WANG定义了一个模式S-T
CREATE SCHEMA <模式名> AUTHORIZATION <用户名>
[例2]
CREATE SCHEMA AUTHORIZATION WANG
如果没有指定<模式名>,那么<模式名>隐含为<用户名>
- 在这个空间中可以定义该模式包含的数据库对象,例如基本表、视图、索引等。
- 在CREATE SCHEMA中可以接受CREATE TABLE(表),CREATE VIEW(视图)和GRANT(授权)子句。格式如下:
CREATE SCHEMA <模式名> AUTHORIZATION <用户名>[<表定义子句>|<视图定义子句>|<授权定义子句>]
[例3]为用户ZHANG创建了一个模式TEST,并在其中定义了一个表TAB1
CREATE SCHEMA TEST AUTHORIZATION ZHANG
CREATE TABLE TAB1(COL1 SMALLINT,
COL2 INT,
COL3 CHAR(20),
COL4 NUMERIC(10,3),
COL5 DECIMAL(5,2)
);
- 执行创建模式语句必须拥有DBA权限,或者DBA授予在CREATE SCHEMA的权限。
- 删除模式
语句格式:
DROP SCHEMA <模式名> <CASCADE|RESTRICT>
说明:
- CASCADE和RESTRICT必须二选一
- CASCADE(级联)
- 定义:删除模式的同时把该模式中所有的数据库对象全部删除
- RESTRICT(限制)
- 如果该模式中定义了下属的数据库对象(如表、视图等),则拒绝该删除语句的执行。当该模式中没有任何下属的对象时 才能执行。
- 举例:拆除一个房子必须先把房子里面的家具清空了才能拆除
[例4]
DROP SCHEMA ZHANG CASCADE;
删除模式ZHANG,同时该模式中定义的表TAB1也被删除
3.3.2 基本表的定义、删除与修改
- 定义基本表
CREATE TABLE <表名>
(<列名> <数据类型>[ <列级完整性约束条件> ]
[,<列名> <数据类型>[ <列级完整性约束条件>] ] …
[,<表级完整性约束条件> ] );
如果完整性约束条件涉及到该表的多个属性列,则必须定义在表级上,否则既可以定义在列级也可以定义在表级。
[例5] 建立“学生”表Student,学号是主码,姓名取值唯一。
CREATE TABLE Student
(Sno CHAR(9) PRIMARY KEY, /* 列级完整性约束条件*/
Sname CHAR(20) UNIQUE, /* Sname取唯一值*/
Ssex CHAR(2),
Sage SMALLINT,
Sdept CHAR(20)
);/*CHAR是数据类型,后面会讲*/
[例6] 建立一个“课程”表Course
CREATE TABLE Course
( Cno CHAR(4) PRIMARY KEY,
Cname CHAR(40),
Cpno CHAR(4) , /*先导课*/
Ccredit SMALLINT,
FOREIGN KEY (Cpno) REFERENCES Course(Cno)
);
Cpno是外码,被参照表是Course,被参照列是Cno
[例7] 建立一个“学生选课”表SC
CREATE TABLE SC
(Sno CHAR(9),
Cno CHAR(4),
Grade SMALLINT,
PRIMARY KEY (Sno,Cno),
/* 主码由两个属性构成,必须作为表级完整性进行定义*/
FOREIGN KEY (Sno) REFERENCES Student(Sno),
/* 表级完整性约束条件,Sno是外码,被参照表是Student */
FOREIGN KEY (Cno) REFERENCES Course(Cno)
/* 表级完整性约束条件, Cno是外码,被参照表是Course*/
);
- 数据类型
- 模式与表
- 每一个基本表都属于某一个模式,一个模式包含多个基本表
定义基本表所属模式有以下三种方式
- 方法一:在表名中明显地给出模式名
- Create table “S-T”.Student(…); /模式名为 S-T/
- Create table “S-T”.Cource(…);
- Create table “S-T”.SC(…);
- 方法二:在创建模式语句中同时创建表
- 方法三:设置所属的模式
创建基本表(其他数据库对象也一样)时,若没有指定模式,系统根据搜索路径来确定该对象所属的模式
- 显示当前的搜索路径
SHOW search_path;
- 搜索路径的当前默认值是:
$user, PUBLIC
- DBA用户可以设置搜索路径,然后定义基本表
SET search_path TO “S-T”,PUBLIC;
若搜索路径中的模式名都不存在,系统将给出错误
RDBMS会使用模式列表中第一个存在的模式作为数据库对象的模式名
[例8] DBA用户设置搜索路径,然后定义基本表
SET search_path TO “S-T”,PUBLIC;
Create table Student(......);
结果建立了S-T.Student基本表。
小总结:数据库可以有多个模式,相当于仓库里面有多个房间,每个模式下面可以有多个表,相当于一个房间里面可以放很多零件。数据库会把模式授权给一个管理员,由其对模式下面的数据进行操作,相当于每个房间有个管理员,由其管理房间内的物品。
- 修改基本表
语法格式:
ALTER TABLE <表名>
[ ADD [ COLUMN ] <新列名> <数据类型> [ 完整性约束 ] ]
[ ADD <表级完整性约束>]
[ DROP [ COLUMN ] <列名> [CASCADE| RESTRICT] ]
[ DROP CONSTRAINT <完整性约束名> [ RESTRICT | CASCADE ] ]
[ ALTER COLUMN <列名><数据类型> ] ;
说明:
- <表名>是要修改的基本表。
- ADD子句用于增加新列、新的列级完整性约束条件和新的表级完整性约束条件。
- DROP COLUMN子句用于删除表中的列。
- 如果指定了CASCADE短语,则自动删除引用了该列的其他对象。
- 如果指定了RESTRICT短语,则如果该列被其他对象引用,关系数据库管理系统将拒绝删除该列。
- DROP CONSTRAINT子句用于删除指定的完整性约束条件。
- ALTER COLUMN子句用于修改原有的列定义,包括修改列名和数据类型。
[例9] 向Student表增加“入学时间”列,其数据类型为日期型。
ALTER TABLE Student
ADD S_entrance DATE;
不论基本表中原来是否已有数据,新增加的列一律为空值。
[例10] 将年龄的数据类型由字符型(假设原来的数据类型是字符型)改为整数。
ALTER TABLE Student
ALTER COLUMN Sage INT;
[例11] 增加课程名称必须取唯一值的约束条件。
ALTER TABLE Course
ADD UNIQUE(Cname);
- 删除基本表
语句格式:
DROP TABLE <表名>[RESTRICT| CASCADE];
- RESTRICT:删除表是有限制的。
- 欲删除的基本表不能被其他表的约束所引用
- 如果存在依赖该表的对象,则此表不能被删除
- CASCADE:删除该表没有限制。
- 在删除基本表的同时,相关的依赖对象一起删除
[例12] 删除Student表
DROP TABLE Student CASCADE ;
DROP TABLE时,SQL99 与 3个RDBMS的处理策略比较:
DROP TABLE时,SQL2011 与 3个RDBMS的处理策略比较:
3.3.3 索引的建立与删除
-
建立索引的目的:加快查询速度(相当于书的目录)
-
谁可以建立索引
- DBA 或 表的属主(即建立表的人)
- DBMS一般会自动建立以下列上的索引
- PRIMARY KEY
- UNIQUE
-
谁维护索引
- DBMS自动完成
-
使用索引
- DBMS自动选择是否使用索引以及使用哪些索引
-
RDBMS(关系数据库管理系统)中索引一般采用B+树、HASH索引来实现
- B+树索引具有动态平衡的优点
- HASH索引具有查找速度快的特点
-
采用B+树,还是HASH索引 则由具体的RDBMS来决定
-
索引是关系数据库的内部实现技术,属于内模式的范畴
-
CREATE INDEX语句定义索引时,可以定义索引是唯一索引、非唯一索引或聚簇索引
一、建立索引
语句格式
CREATE [UNIQUE] [CLUSTER] INDEX <索引名> ON <表名>(<列名>[<次序>][,<列名>[<次序>] ]…);
- UNIQUE表明此索引每一个索引值只对应唯一的数据
- CLUSTER表示要建立的索引是聚簇索引。聚簇索引是指索引顺序与表中记录的物理顺序一致的索引组织。
[例13] 为学生-课程数据库中的Student,Course,SC三个表建立索引。
CREATE UNIQUE INDEX Stusno ON Student(Sno);
CREATE UNIQUE INDEX Coucno ON Course(Cno);
CREATE UNIQUE INDEX SCno ON SC(Sno ASC,Cno DESC);
Student表按学号升序建唯一索引
Course表按课程号升序建唯一索引
SC表按学号升序和课程号降序建唯一索引
[例14] 在Student表的Sname(姓名)列上建立一个聚簇索引
CREATE CLUSTER INDEX Stusname ON Student(Sname);
- 在最经常查询的列上建立聚簇索引以提高查询效率
- 一个基本表上最多只能建立一个聚簇索引
- 经常更新的列不宜建立聚簇索引
**二、删除索引 **
语句格式:
DROP INDEX <索引名>;
删除索引时,系统会从数据字典中删去有关该索引的描述。
[例15] 删除Student表的Stusname索引
DROP INDEX Stusname;
三、修改索引
语句格式
ALTER INDEX <旧索引名> RENAME TO <新索引名>;
3.3.4 数据字典
- 数据字典是关系数据库管理系统内部的一组系统表
- 它记录了数据库中所有的定义信息,包括关系模式定义、视图定义、索引定义、完整性约束定义、各类用户对数据库的操作权限、统计信息等。
- 关系数据库管理系统在执行SQL 的数据定义语句时,实际上就是在更新数据字典表中的相应信息。
3.4 数据查询(重要)
语句格式
SELECT [ALL|DISTINCT] <目标列表达式>
[,<目标列表达式>] …
FROM <表名或视图名>[, <表名或视图名> ] …
[ WHERE <条件表达式> ]
[ GROUP BY <列名1> [ HAVING <条件表达式> ] ]
[ ORDER BY <列名2> [ ASC|DESC ] ];
3.4.1 单表查询
功能:查询仅涉及一个表的内容
一,选择表中若干列
-
查询指定列
- 格式:在SELECT后面指定列名,FROM后面列所在的表名
[例1] 查询全体学生的学号与姓名
SELECT Sno,Sname FROM Student;
[例2] 查询全体学生的姓名、学号、所在系。
SELECT Sname,Sno,Sdept FROM Student;
-
查询全部列
- 功能:选出所有属性列
- 格式:在SELECT关键字后面列出所有列名,或将<目标列表达式>指定为 *
[例3] 查询全体学生的详细记录。
SELECT Sno,Sname,Ssex,Sage,Sdept FROM Student; 或 SELECT * FROM Student;
-
查询经过计算的值
- 功能:选出表中指定的属性列,并经过计算后输出。
- 格式:SELECT子句的<目标列表达式>可以为:
- 算术表达式
- 字符串常量
- 函数
- 列别名
[例4] 查全体学生的姓名及其出生年份。
SELECT Sname,2004-Sage /*假定当年的年份为2004年*/ FROM Student;
输出结果:
[例5] 查询全体学生的姓名、出生年份和所有系,要求用小写字母表示所有系名
SELECT Sname,'Year of Birth:',2004-Sage,LOWER(Sdept) FROM Student;
输出结果:
[例6] 使用列别名改变查询结果的列标题:
SELECT Sname NAME,'Year of Birth:' BIRTH,2000-Sage BIRTHDAY,LOWER(Sdept) DEPARTMENT
FROM Student;
加一个空格即可用后面的名字当做列别名
输出结果:
二,选择表中若干元组
- 消除取值重复的行
如果没有指定DISTINCT关键词,则缺省为ALL
SELECT Sno FROM SC;
等价于:
SELECT ALL Sno FROM SC;
如果要消除重复行,则加上DISTINCT:
SELECT DISTINCT Sno
FROM SC;
2. 查询满足条件的元组
查询满足条件的元组可以通过where子句实现,where常用的询条件如下:
1)比较查询
例:查询计算机科学系全体学生的名单。
SELECT Sname
FROM Student
WHERE Sdept='CS';
例:查询所有年龄在20岁以下的学生姓名及其年龄。
SELECT Sname,Sage
FROM Student
WHERE Sage < 20;
例:查询考试成绩有不及格的学生的学号。
SELECT DISTINCT Sno
FROM SC
WHERE Grade<60;
注意要用distinct,去重复
补充一个在c++也会犯的错误,比如题目要求年龄在10到12岁之间(包括),如果在where后面使用10<=age<=12是错误的用法,应该是10<=age AND age<=12,这个用法在c++也是错误的,在python里面可以使用
2)确定范围
- 谓词:
BETWEEN … AND …
NOT BETWEEN … AND …
例:查询年龄在20~23岁(包括20岁和23岁)之间的学生的姓名、系别和年龄
SELECT Sname,Sdept,Sage
FROM Student
WHERE Sage BETWEEN 20 AND 23;
不在这个范围内只需在between前加个not
3)确定集合
- 谓词
IN <值表>
NOT IN <值表>
例:查询信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别。
SELECT Sname,Ssex
FROM Student
WHERE Sdept IN ( 'IS','MA','CS' );
不在这个集合只需在in前加个not即可
4)字符匹配
- 谓词
[NOT] LIKE ‘<匹配串>’ [ESCAPE ‘ <换码字符>’]
1.匹配串为固定字符串
例:查询学号为200215121的学生的详细情况。
SELECT *
FROM Student
WHERE Sno LIKE '200215121';
等价于
SELECT *
FROM Student
WHERE Sno = '200215121';
2.匹配串为含通配符的字符串
例:查询所有姓刘学生的姓名、学号和性别。
SELECT Sname,Sno,Ssex
FROM Student
WHERE Sname LIKE '刘%';
%代表任意长度字符串
如果要查指定长度的
例:查询姓"欧阳"且全名为三个汉字的学生的姓名。
SELECT Sname
FROM Student
WHERE Sname LIKE '欧阳_';
一个_代表一个字符
3.使用换码字符将通配符转义为普通字符
例:查询DB_Design课程的课程号和学分。
SELECT Cno,Ccredit
FROM Course
WHERE Cname LIKE 'DB\_Design' ESCAPE '\';
ESCAPE后跟的符号在在like中有实际的意义,所以在这里_并不是单个字符
例:查询以"DB_"开头,且倒数第3个字符为i的课程的详细情况。
SELECT *
FROM Course
WHERE Cname LIKE 'DB\_%i_ _' ESCAPE ' \ ';
说明:ESCAPE ‘\’ 表示“\” 为换码字符
5)涉及空值的查询
- 谓词
IS NULL
IS NOT NULL
- “IS” 不能用 “=” 代替
例:某些学生选修课程后没有参加考试,所以有选课记录,但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号。
SELECT Sno,Cno
FROM SC
WHERE Grade IS NULL
要查有成绩的就在NULL前加not
6) 多重条件查询
- 逻辑运算符:AND和OR来联结多个查询条件
- AND的优先级高于OR
- 可以用括号改变优先级
- 可用来实现多种其他谓词
- [NOT] IN
- [NOT] BETWEEN … AND …
例:查询计算机系年龄在20岁以下的学生姓名。
SELECT Sname
FROM Student
WHERE Sdept= 'CS' AND Sage<20;
三,ORDER BY子句
- ORDER BY子句
- 可以按一个或多个属性列排序
- 升序:
ASC
;降序:DESC
;缺省值为升序
- 当排序列含空值时(默认空值是最大值)
- ASC:排序列为空值的元组最后显示
- DESC:排序列为空值的元组最先显示
例:查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列。
SELECT Sno,Grade
FROM SC
WHERE Cno='3'
ORDER BY Grade DESC;
例:查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列。
SELECT *
FROM Student
ORDER BY Sdept ASC(可缺省),Sage DESC;
四,聚集函数
-
计数
COUNT([DISTINCT|ALL] *)
统计元组个数COUNT([DISTINCT|ALL] <列名>)
统计一列中值的个数
-
计算总和
SUM([DISTINCT|ALL] <列名>)
计算一列值的总和(为数值)
-
计算平均值
-
AVG([DISTINCT|ALL] <列名>)
计算一列值的平均值(为数值) -
最大最小值
MAX([DISTINCT|ALL] <列名>)
求一列值的最大值(为数值)MIN([DISTINCT|ALL] <列名>)
求一列值的最小值(为数值)
例:查询学生总人数
SELECT COUNT(*)
FROM Student;
例:查询选修了课程的学生人数。
SELECT COUNT(DISTINCT Sno)
FROM SC;
例:计算1号课程的学生平均成绩。
SELECT AVG(Grade)
FROM SC
WHERE Cno= ' 1 ';
例:查询选修1号课程的学生最高分数。
SELECT MAX(Grade)
FROM SC
WHER Cno= ‘ 1 ’;
例:查询学生200215012选修课程的总学分数。
SELECT SUM(Ccredit)
FROM SC,Course
WHERE Sno='200215012' AND SC.Cno=Course.Cno;
自然连接,后面讲
当聚集函数遇到空值时,除COUNT(*)外,都跳过空值而处理非空值。
注意:聚集函数不能写在where语句中,只能写在select后和group by的having子句
五、GROUP BY子句
按指定的一列或多列值分组,值相等的为一组,细化聚集函数的作用对象
- 未对查询结果分组,聚集函数将作用于整个查询结果
- 对查询结果分组后,聚集函数将分别作用于每个组
- 作用对象是查询的中间结果表
注意:使用group by时,select后面跟的可以是聚集函数或者group by后面的值,不能为第三中情况,比如下面这个例子不能在select后加Sno
例:求各个课程号及相应的选课人数。
SELECT Cno,COUNT(Sno)
FROM SC
GROUP BY Cno;
例:查询选修了3门以上课程的学生学号。
SELECT Sno
FROM SC
GROUP BY Sno
HAVING COUNT(*) >3;
- WHERE子句作用于基表或视图,从中选择满足条件的元组;
- where语句不能有聚集函数
- HAVING短语作用于组,从中选择满足条件的组。
3.4.2 连接查询
一、等值与非等值连接查询
格式:
- [<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2>
- 比较运算符有>,<,=,
- [<表名1>.]<列名1> BETWEEN [<表名2>.]<列名2> AND [<表名2>.]<列名3>
连接字段:连接谓词中的列名称
连接条件中的各连接字段类型必须是可比的,但名字不必是相同的
等值连接:
- 连接运算符为=
例:查询每个学生及其选修课程的情况
SELECT Student.*,SC.*
FROM Student,SC
WHERE Student.Sno = SC.Sno;
去掉重复列相当于自然连接
二、自身连接
- 一个表与其自己进行连接
- 需要给表起别名以示区别
- 由于所有属性名都是同名属性,因此必须使用别名前缀
例:查询每一门课的间接先修课(即先修课的先修课)
SELECT FIRST.Cno,SECOND.Cpno
FROM Course FIRST,Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;
三、外连接
外连接与普通连接的区别
- 普通连接操作只输出满足连接条件的元组
- 外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出
外连接分为:
- 左外连接:列出左边关系中所有的元组。
LEFT OUT JOIN SC ON
- 右外连接:列出右边关系中所有的元组。
RIGHT OUT JOIN SC ON
四,多表连接
连接操作是两个以上的表进行连接。
五、复合条件连接
复合条件连接:WHERE子句中含多个连接条件
例:查询选修2号课程且成绩在90分以上的所有学生
SELECT Student.Sno, Sname
FROM Student, SC
WHERE Student.Sno = SC.Sno AND
/* 连接谓词*/
SC.Cno= ‘2’ AND SC.Grade > 90;
/* 其他限定条件 */
3.4.3 嵌套查询
- 一个SELECT-FROM-WHERE语句称为一个查询块
- 将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询称为嵌套查询
说明:
- 子查询不能使用ORDER BY子句
- 层层嵌套方式反映了SQL语言的结构化
- 有些嵌套查询可以用连接运算替代
一、带有IN谓词的子查询
在嵌套查询中,子查询的结果往往是个集合,用IN谓词表示父查询的条件在子查询结果的集合中。
例: 查询与“刘晨”在同一个系学习的学生。
① 确定“刘晨”所在系名
SELECT Sdept
FROM Student
WHERE Sname='刘晨';
② 查找所有在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 = '刘晨';
- 不相关子查询
- 子查询的查询条件不依赖于父查询
- 相关子查询:
- 子查询的查询条件依赖于父查询
二、 带有比较运算符的子查询
- 当能确切知道内层查询返回单值时,可用比较运算符(>,<,=,>=,<=,!=或< >)。
- 与ANY或ALL谓词配合使用
例:找出每个学生超过他选修课程平均成绩的课程号。(这里有点绕,多看会)(期中考了这道原题,印象深刻)
SELECT Sno,Cno
FROM SC x
WHERE Grade >=(SELECT AVG(Grade)
FROM SC y
WHERE y.Sno=x.Sno);
三、 带有ANY(SOME)或ALL谓词的子查询
- 谓词语义
- ANY:任意一个值
- ALL:所有值
例:查询其他系中比计算机科学某一学生年龄小的学生姓名和年龄
SELECT Sname,Sage
FROM Student
WHERE Sage<ANY (SELECT max(sage)
FROM Student
WHERE Sdept= ' CS ')
AND Sdept <> 'CS' ; /*父查询块中的条件 */
例:查询其他系中比计算机科学系所有学生年龄都小的学生姓名及年龄。
SELECT Sname,Sage
FROM Student
WHERE Sage < ALL
(SELECT sage
FROM Student
WHERE Sdept= ' CS ')
AND Sdept <> ' CS ’;
用聚集函数实现子查询要比直接用ANY、ALL效率更高。ANY(或SOME),ALL谓词与聚集函数、IN谓词的等价转换关系
四、 带有EXISTS谓词的子查询
EXISTS谓词
- 存在量词 ∃
- 带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”。
- 若内层查询结果非空,则外层的WHERE子句返回真值
- 若内层查询结果为空,则外层的WHERE子句返回假值
- 由EXISTS引出的子查询,其目标列表达式通常都用* ,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义
NOT EXISTS谓词
- 若内层查询结果非空,则外层的WHERE子句返回假值
- 若内层查询结果为空,则外层的WHERE子句返回真值
不同形式的查询间的替换
- 一些带EXISTS或NOT EXISTS谓词的子查询不能被其他形式的子查询等价替换
- 所有带IN谓词、比较运算符、ANY和ALL谓词的子查询都能用带EXISTS谓词的子查询等价替换
用EXISTS/NOT EXISTS实现全称量词(难点)
-
SQL语言中没有全称量词 ∀ (For all)
-
可以把带有全称量词的谓词转换为等价的带有存在量词的谓词:
( ∀ x ) P ≡ ﹁ ( ∃ x ( ﹁ P ) ) (∀ x)P ≡ ﹁ (∃ x(﹁ P)) (∀x)P≡﹁(∃x(﹁P))
用EXISTS/NOT EXISTS实现逻辑蕴函(难点)
-
SQL语言中没有蕴函(Implication)逻辑运算
-
可以利用谓词演算将逻辑蕴函谓词等价转换为:
p → q ≡ ﹁ p ∨ q p \rightarrow q ≡ ﹁ p∨q p→q≡﹁p∨q
3.4.4 集合查询
集合操作的种类(期中考试考过一种)
- 并操作UNION
- UNION:将多个查询结果合并起来时,系统自动去掉重复元组。
- UNION ALL:将多个查询结果合并起来时,保留重复元组
- 交操作INTERSECT
- 差操作EXCEPT
参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同
例:查询计算机科学系的学生及年龄不大于19岁的学生。
SELECT *
FROM Student
WHERE Sdept= 'CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19;
方法2:
SELECT DISTINCT *
FROM Student
WHERE Sdept= 'CS' OR Sage<=19;
例:查询计算机科学系的学生与年龄不大于19岁的学生的交集
SELECT *
FROM Student
WHERE Sdept='CS'
INTERSECT
SELECT *
FROM Student
WHERE Sage<=19
例: 查询计算机科学系的学生与年龄不大于19岁的学生的差集。
SELECT *
FROM Student
WHERE Sdept='CS'
EXCEPT
SELECT *
FROM Student
WHERE Sage <=19;
3.4.5 SELECT语句的一般格式
SELECT [ALL|DISTINCT]
<目标列表达式> [别名] [ ,<目标列表达式> [别名]] …
FROM <表名或视图名> [别名]
[ ,<表名或视图名> [别名]] …
[WHERE <条件表达式>]
[GROUP BY <列名1>
[HAVING <条件表达式>]]
[ORDER BY <列名2> [ASC|DESC]
3.5 数据更新
3.5.1 插入数据
两种插入数据方式
-
插入元组
-
插入子查询结果
一、插入元组
语句格式
INSERT
INTO <表名> [(<属性列1>[,<属性列2 >…)]
VALUES (<常量1> [,<常量2>] … )
功能:将新元组插入指定表中
- INTO子句
- 属性列的顺序可与表定义中的顺序不一致
- 没有指定属性列,默认插入全部
- 指定部分属性列
- VALUES子句
- 提供的值必须与INTO子句匹配
- 值的个数,值的类型要与属性列一致
例:将一个新学生元组(学号:200215128;姓名:陈冬;性别:男;所在系:IS;年龄:18岁)插入到Student表中。
INSERT
INTO Student (Sno,Sname,Ssex,Sdept,Sage)
VALUES ('200215128','陈冬','男','IS',18);
例: 将学生张成民的信息插入到Student表中。
INSERT
INTO Student
VALUES ('200215126', '张成民', '男',18,'CS');
例:插入一条选课记录( ‘200215128’,'1 ')。
INSERT
INTO SC(Sno,Cno)
VALUES ('200215128','1');
RDBMS将在新插入记录的Grade列上自动地赋空值。
二、插入子查询结果
语句格式
INSERT
INTO <表名> [(<属性列1> [,<属性列2>… )]
子查询;
功能:将子查询结果插入指定表中
- SELECT子句目标列必须与INTO子句匹配
例:对每一个系,求学生的平均年龄,并把结果存入数据库。
第一步:建表
CREATE TABLE Dept_age
(Sdept CHAR(15) /* 系名*/
Avg_age SMALLINT); /*学生平均年龄*/
第二步:插入数据
INSERT
INTO Dept_age(Sdept,Avg_age)
SELECT Sdept,AVG(Sage)
FROM Student
GROUP BY Sdept;
- RDBMS在执行插入语句时会检查所插元组是否破坏表上已定义的完整性规则
3.5.2 修改数据
语句格式
UPDATE <表名>
SET <列名>=<表达式>[,<列名>=<表达式>]…
[WHERE <条件>];
功能:修改指定表中满足WHERE子句条件的元组
- SET子句
- 指定修改方式
- 要修改的列
- 修改后取值
- WHERE子句
- 指定要修改的元组
- 缺省表示要修改表中的所有元组
1. 修改某一个元组的值
例:将学生200215121的年龄改为22岁
UPDATE Student
SET Sage=22
WHERE Sno=' 200215121 ';
2. 修改多个元组的值
例:将所有学生的年龄增加1岁
UPDATE Student
SET Sage= Sage+1;
3. 带子查询的修改语句
例:将计算机科学系全体学生的成绩置零。
UPDATE SC
SET Grade=0
WHERE 'CS'=
(SELETE Sdept
FROM Student
WHERE Student.Sno = SC.Sno);
3.5.3 删除数据
语句格式
DELETE
FROM <表名>
[WHERE <条件>];
功能:删除指定表中满足WHERE子句条件的元组
- WHERE子句
- 指定要删除的元组
- 缺省表示要删除表中的全部元组,表的定义仍在字典中
1. 删除某一个元组的值
例:删除学号为200215128的学生记录。
DELETE
FROM Student
WHERE Sno= '200215128';
2. 删除多个元组的值
例:删除所有的学生选课记录。
DELETE
FROM SC;
3. 带子查询的删除语句
例:删除计算机科学系所有学生的选课记录。
DELETE
FROM SC
WHERE 'CS'=
(SELETE Sdept
FROM Student
WHERE Student.Sno=SC.Sno);
3.6 空值的处理
空值的存在是因为取值有不确定性,对关系运算带来特殊的问
题,所以需要做特殊的处理。
SQL语言中允许某些元组的某些属性取空值,一般有以下三种情况:
- 该属性有值,但当前不知道它的具体值。
- 该属性不应该有值。
- 由于某种原因不便于填写。
判断一个属性的值是否为空值,用IS NULL
或IS NOT NULL
来表示
- 属性定义中有NOT NULL约束条件的不能取空值
- 加了UNIQUE限制的属性不能取空值
- 码不能取空值
算术运算:空值与另一个值(包括另一个空值)的算术运算的结果为空值;
比较运算:空值与另一个值(包括另一个空值)的比较结果为UNKNOWN;
3.7 视图
视图的特点
- 虚表,是从一个或几个基本表(或视图)导出的表
- 只存放视图的定义,不存放视图对应的数据
- 基表中的数据发生变化,从视图中查询出的数据也随之改变
3.7.1 定义视图
一、建立视图
语句格式:
CREATE VIEW
<视图名> [(<列名> [,<列名>]…)]
AS <子查询>
[WITH CHECK OPTION];
-
WITH CHECK OPTION表示对视图进行UPDATE,INSERT和DELETE操作时要保证更新,插入或删除的行满足视图定义中的谓词条件
-
组成视图的属性列名:全部省略或全部指定
-
子查询不允许含有ORDER BY子句和DISTINCT短语
-
RDBMS执行CREATE VIEW语句时只是把视图定义存入数据字典,并不执行其中的SELECT语句。
-
在对视图查询时,按视图的定义从基本表中将数据查出。
例:建立信息系学生的视图
CREATE VIEW IS_Student
AS
SELECT Sno,Sname,Sage
FROM Student
WHERE Sdept= 'IS';
例:建立信息系学生的视图,并要求进行修改和插入操作时仍需保证该视图只有信息系的学生
CREATE VIEW IS_Student
AS
SELECT Sno,Sname,Sage
FROM Student
WHERE Sdept= 'IS'
WITH CHECK OPTION;
- 对IS_Student视图的更新操作:
- 修改操作:自动加上Sdept= 'IS’的条件
- 删除操作:自动加上Sdept= 'IS’的条件
- 插入操作:自动检查Sdept属性值是否为’IS’
- 如果不是,则拒绝该插入操作
- 如果没有提供Sdept属性值,则自动定义Sdept为’IS’
例:建立信息系选修了1号课程的学生视图。(基于多个表)
CREATE VIEW IS_S1(Sno,Sname,Grade)
AS
SELECT Student.Sno,Sname,Grade
FROM Student,SC
WHERE Sdept= 'IS' AND
Student.Sno=SC.Sno AND
SC.Cno= '1';
二、删除视图
语句的格式:
DROP VIEW <视图名>;
- 该语句从数据字典中删除指定的视图定义
- 如果该视图上还导出了其他视图,使用CASCADE级联删除语句,把该视图和由它导出的所有视图一起删除
- 删除基表时,由该基表导出的所有视图定义都必须显式地使用DROP VIEW语句删除
删除视图IS_S1:
DROP VIEW IS_S1;
会报错,因为IS_S1视图上还导出了IS_S2视图,使用级联删除
DROP VIEW IS_S1 CASCADE;
3.7.2 查询视图
- 用户角度:查询视图与查询基本表相同
视图消解:关系数据库管理系统执行对视图的查询时,首先进行有效性检查,检查查询中涉及的表、视图等是否存在。如果存在,则从数据字典中取出视图的定义,把定义中的子查询和用户的查询结合起来,转换成等价的对基本表的查询,然后再执行修正了的查询。这一转换过程称为视图消解(view resolution)。
例:在信息系学生的视图中找出年龄小于20岁的学生
SELECT Sno,Sage
FROM IS_Student
WHERE Sage<20;
视图消解转换后的查询语句为:
SELECT Sno,Sage
FROM Student
WHERE Sdept= 'IS' AND Sage<20;
视图消解法的局限:有些情况下,视图消解法不能生成正确查询。
3.7.3 更新视图
例:将信息系学生视图IS_Student中学号200215122的学生姓名改为“刘辰”
UPDATE IS_Student
SET Sname= '刘辰'
WHERE Sno= ' 200215122 ';
转换后的语句:
UPDATE Student
SET Sname= '刘辰'
WHERE Sno= ' 200215122 ' AND Sdept= 'IS';
更新视图的限制:一些视图是不可更新的,因为对这些视图的更新不能唯一地有意义地转换成对相应基本表的更新
3.7.4 视图的作用
-
视图能够简化用户的操作
-
视图使用户能以多种角度看待同一数据
-
图对重构数据库提供了一定程度的逻辑独立性
-
视图能够对机密数据提供安全保护
-
适当的利用视图可以更清晰的表达查询