第三章 关系数据库标准语言SQL 3.1 SQL概述 3.2 学生课程数据库 3.3 数据定义 3.4 数据查询 3.5 数据更新 3.6 视图
3.1 SQL概述 一、SQL的产生与发展 1974年IBM圣约瑟实验室的Boyce和Chamberlin为关系数据库管理系统设计的一种查询语言,当时称为SEQUEL语言 (Structured English Query Language),后简称为SQL; 1986年ANSI(美国国家标准局)着手制定SQL标准-SQL86; SQL86主要内容:模式定义、数据操作、嵌入式SQL等内容 1987年,ISO(国际标准组织) 通过SQL86标准; 后来经过了SQL89、SQL92、SQL99、SQL2003的发展 ,
二、SQL的特点 1. 综合统一 2. 高度非过程化 3. 面向集合的操作方式 4. 以同一种语法结构提供两种使用方法 5. 语言简洁,易学易用
三、SQL的基本概念 SQL 视图1 视图2 基本表1 基本表2 基本表3 基本表4 存储文件1 存储文件2 外模式 模式 内模式
3.2 学生-课程数据库 Student Course SC 课程号 Cno 课程名 Cname 先行课 Cpno 学分 Ccredit 1 3.2 学生-课程数据库 Student Course 学 号 Sno 姓 名 Sname 性 别 Ssex 年 龄 Sage 所 在 系 Sdept 200215121 李勇 男 20 CS 200215122 刘晨 女 19 IS 200215123 王敏 18 MA 200215125 张立 课程号 Cno 课程名 Cname 先行课 Cpno 学分 Ccredit 1 数据库 5 4 2 数学 3 信息系统 操作系统 6 数据结构 7 数据处理 PASCAL语言 SC 学 号 Sno 课 程 号 Cno 成 绩 Grade 200215121 1 92 2 85 3 88 200215122 90 80
3.3 数 据 定 义 表3.2 SQL的数据定义语句 操作对象 操 作 方 式 创建 删除 修改 模式 CREATE SCHEMA 3.3 数 据 定 义 表3.2 SQL的数据定义语句 操作对象 操 作 方 式 创建 删除 修改 模式 CREATE SCHEMA DROPCH EMA 表 CREATE TABLE DROP TABLE ALTER TABLE 视图 CREATE VIEW DROP VIEW 索引 CREATE INDEX DROP INDEX
CREATE SCHEMA <模式名> 3.3.1 模式的定义与删除 一、定义模式 CREATE SCHEMA <模式名> AUTHORIZATION<用户名> [例如1] 定义一学生-课程模式 CREATE SCHEMA “S-T” AUTHORIZATION WANC 或 CREATE SCHEMA AUTHORIZATION WANC 定义模式实际上定义了一个命名空间,在这个空间中可以进一步定义该模式包含的数据库对象,例如基本表、视图、索引等。
3.3.1 模式的定义与删除 可以在模式创建的同时在这个模式中定义中进一步创建基本表、视图、定义授权。 CREATE SCHEMA <模式名> AUTHORIZATION<用户名> [<表定义子句>|<视图定义子句>|<授权定义子句>] [例如3] CREATE SCHEMA TEST AUTHORIZATION ZHANG CREATE TABLE TAB1 (COL1 SMALLINT, COL2 INT COL3 CHAR(20) COL4 DATE COL5 CHAR(20) );
DROP SCHEMA <模式名> 3.3.1 模式的定义与删除 二、删除模式 DROP SCHEMA <模式名> <CASCADE|RESTRICT> 其中:CASCADE: 联级 RESTRICT:限制 [例如4] DROP SCHEMA ZHANG CASCAD
3.3.2 基本表的定义、删除与修改 一、定义基本表 CREATE TABLE <表名> (<列名> <数据类型>[ <列级完整性约束条件> ] [,<列名> <数据类型>[ <列级完整性约束条件>] ] … [,<表级完整性约束条件> ] ); <表名>:所要定义的基本表的名字 <列名>:组成该表的各个属性(列) <列级完整性约束条件>:涉及相应属性列的完整性约束条件 <表级完整性约束条件>:涉及一个或多个属性列的完整性约束条件
例题 [例5] 建立一个“学生”表Student,它由学号Sno、姓名Sname、性别Ssex、年龄Sage、所在系Sdept五个属性组成。其中学号为主码,并且姓名取值也唯一。 CREATE TABLE Student (Sno CHAR(9) PRIMARY KEY, Sname CHAR(20) UNIQUE, Ssex CHAR(2) , Sage SMALLINT, Sdept CHAR(20) ); 常用完整性约束 主码约束: PRIMARY KEY 唯一性约束:UNIQUE 非空值约束:NOT NULL 外码:FOREIGN KEY 参照完整性约束
例题 [例6] 建立一个“课程”表Course。 CREATE TABLE Course (Cno CHAR(4) PRIMARY KEY , Cname CHAR(40), Cpno CHAR(4), Ccredit SMALLINT, FOREIGN KEY (Cpno) REFERENCES Course(Cno) );
例题 [例7] 建立一个“学生选课”表SC,它由学号Sno、课程号Cno,修课成绩Grade组成,其中(Sno, Cno)为主码。 CREATE TABLE SC (Sno CHAR(9) , Cno CHAR(4) , Grade SMALLINT, PRIMARY key (Sno, Cno), FOREIGN KEY (Sno) REFERENCES Student(Sno), FOREIGN KEY (Cno) REFERENCES Course(Cno) );
二、数据类型 注意:不同的DBMS支持的数据类型不完全相同 CHAR(n) 长度为n的定长字符串。 VARCHAR(n) 最大长度为n的变长字符串。 INT 全字长二进制整数。 SMALLINT 半字长二进制整数。 FLOAT 双字长浮点数。 DATE 日期型,格式为YYYY-MM-DD。 TIME 时间型,格式为HH.MM.SS。 TIMESTAMP 日期加时间。 注意:不同的DBMS支持的数据类型不完全相同
SQL Server的数据类型(P40) 1. 整型数据类型 6. 货币数据类型 2. 浮点数据类型 7. 位数据类型 3. 字符数据类型 4. 日期和时间数据类型 5. 文本和图形数据类型 6. 货币数据类型 7. 位数据类型 8. 二进制数据类型 9. 特殊数据类型 10. 新增数据类型
三、模式与表 每一个基本表都属于某一个模式,一个模式包含多个基本表。有三种方法定义基本表所属的模式。 方法一:在表名中明显的给出模式名 CREATE TABLE “S-T”.Stuent(……); CREATE TABLE “S-T”. Course(……); CREATE TABLE “S-T”.SC(……); 方法二:在创建模式语句中同时创建表(如:例3) 方法三:设置所属的模式 Set scarch_path to “S-T”,PUBLIC
四、修改基本表 ALTER TABLE <表名> [ ADD <新列名> <数据类型> [ 完整性约束 ] ] [ DROP <完整性约束名> ] [ALTER <列名> <数据类型> ]; <表名>:要修改的基本表 ADD子句:增加新列和新的完整性约束条件 DROP子句:删除指定的完整性约束条件 ALTER子句:用于修改列名和数据类型 说明:标准SQL没有删除列的功能。
例题 [例8] 向Student表增加“入学时间”列,其数据类型为日期型。 不论基本表中原来是否已有数据,新增加的列一律为空值。 ALTER TABLE Student ADD Scome DATE; 不论基本表中原来是否已有数据,新增加的列一律为空值。 [例9] 将年龄的数据类型改为整数。 ALTER TABLE Student MODIFY Sage SMALLINT; 注:修改原有的列定义有可能会破坏已有数据 [例10] 删除学生姓名必须取唯一值的约束。 ALTER TABLE Student DROP UNIQUE(Sname);
五、删除基本表 DROP TABLE <表名>[RESTRICT|CASCADE]; [例11] 删除Student表 DROP TABLE Student ;
3.3.2 建立与删除索引 建立索引是加快查询速度的有效手段 DBA或表的属主(即建立表的人)根据需要建立 3.3.2 建立与删除索引 建立索引是加快查询速度的有效手段 DBA或表的属主(即建立表的人)根据需要建立 有些DBMS自动建立以下列上的索引 PRIMARY KEY UNIQUE 维护索引 DBMS自动完成 使用索引 DBMS自动选择是否使用索引以及使用哪些索引
一、建立索引 语句格式 CREATE [UNIQUE] [CLUSTER] INDEX <索引名> ON <表名>(<列名>[<次序>][,<列名>[<次序>] ]…); 用<表名>指定要建索引的基本表名字 索引可以建立在该表的一列或多列上,各列名之间用逗号分隔 用<次序>指定索引值的排列次序,升序:ASC,降序:DESC。缺省值:ASC UNIQUE表明此索引的每一个索引值只对应唯一的数据记录 CLUSTER表示要建立的索引是聚簇索引
例题 [例13] CREATE CLUSTERED INDEX Stusname ON Student(Sname); [例14] 为学生-课程数据库中的Student,Course,SC三个表建立索引。其中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); 唯一值索引 对于已含重复值的属性列不能建UNIQUE索引 对某个列建立UNIQUE索引后,插入新记录时DBMS会自动检查新记录在该列上是否取了重复值。这相当于增加了一个UNIQUE约束
CREATE CLUSTER INDEX Stusname ON Student(Sname); 聚簇索引 建立聚簇索引后,基表中数据也需要按指定的聚簇属性值的升序或降序存放。也即聚簇索引的索引项顺序与表中记录的物理顺序一致 例: CREATE CLUSTER INDEX Stusname ON Student(Sname); 在Student表的Sname(姓名)列上建立一个聚簇索引,而且Student表中的记录将按照Sname值的升序存放。 在一个基本表上最多只能建立一个聚簇索引 聚簇索引的用途:对于某些类型的查询,可以提高查询效率 聚簇索引的适用范围 很少对基表进行增删操作 很少对其中的变长列进行修改操作
二、删除索引 DROP INDEX Stusname; DROP INDEX <索引名>; 删除索引时,系统会从数据字典中删去有关该索引的描述。 [例15] 删除Student表的Stusname索引。 DROP INDEX Stusname;
3.4 查 询 语句格式 SELECT [ALL|DISTINCT] [TOP n [ PERCENT ]] <目标列表达式> 3.4 查 询 语句格式 SELECT [ALL|DISTINCT] [TOP n [ PERCENT ]] <目标列表达式> [,<目标列表达式>] …[INTO <表名>] FROM <表名或视图名>[, <表名或视图名> ] … [ WHERE <条件表达式> ] [ GROUP BY <列名1> [ HAVING <条件表达式> ] ] [ ORDER BY <列名2> [ ASC|DESC ] ]; SELECT子句:指定要显示的属性列 FROM子句:指定查询对象(基本表或视图) WHERE子句:指定查询条件 GROUP BY子句:对查询结果按指定列的值分组,该属性列值相等的元组为一个组。通常会在每组中作用集函数。 HAVING短语:筛选出只有满足指定条件的组 ORDER BY子句:对查询结果表按指定列值的升序或降序排序
学生-课程数据库 Student Course SC 学生表:Student(Sno,Sname,Ssex,Sage,Sdept) 学 号 Sno 姓 名 Sname 性 别 Ssex 年 龄 Sage 所 在 系 Sdept 200215121 李勇 男 20 CS 200215122 刘晨 女 19 IS 200215123 王敏 18 MA 200215125 张立 课程号 Cno 课程名 Cname 先行课 Cpno 学分 Ccredit 1 数据库 5 4 2 数学 3 信息系统 操作系统 6 数据结构 7 数据处理 PASCAL语言 SC 学 号 Sno 课 程 号 Cno 成 绩 Grade 200215121 1 92 2 85 3 88 200215122 90 80 学生表:Student(Sno,Sname,Ssex,Sage,Sdept) 课程表:Course(Cno,Cname,Cpno,Ccredit) 学生选课表:SC(Sno,Cno,Grade)
3.4.1 单表查询 一、选择表中的若干列 1.查询指定的若干列 2.查询全部列 查询仅涉及一个表,是一种最简单的查询操作 3.4.1 单表查询 查询仅涉及一个表,是一种最简单的查询操作 一、选择表中的若干列 1.查询指定的若干列 [例1] 查询全体学生的学号与姓名。 SELECT Sno,Sname FROM Student; [例2] 查询全体学生的姓名、学号、所在系。 SELECT Sname,Sno,Sdept FROM Student; 2.查询全部列 [例3] 查询全体学生的详细记录。 SELECT Sno,Sname,Ssex,Sage,Sdept FROM Student; 或 SELECT * FROM Student;
3.查询经过计算的值 SELECT 子句的<目标列表达式>为表达式 算术表达式、字符串常量、函数、列别名等 [例4] 查全体学生的姓名及其出生年份。 SELECT Sname,2008-Sage FROM Student; Sname 2008-Sage 李勇 1988 刘晨 1989 王敏 1990 张立 输出结果:
SELECT Sname,'Year of Birth: ',2008-Sage, LOWER(Sdept) FROM Student; [例5] 查询全体学生的姓名、出生年份和所有系,要求用小写字母表示所有系名。 SELECT Sname,'Year of Birth: ',2008-Sage, LOWER(Sdept) FROM Student; 结果为: Sname 'Year of Birth:' 2006-Sage LOWER(Sdept) 李勇 Year of Birth: 1988 cs 刘晨 1989 王名 1990 ms 张立 is
SELECT Sname NAME,'Year of Birth: ’ BIRTH,2006-Sage BIRTHDAY, [例5] 使用列别名改变查询结果的列标题 SELECT Sname NAME,'Year of Birth: ’ BIRTH,2006-Sage BIRTHDAY, ISLOWER(Sdept) DEPARTMENT FROM Student; 输出结果: NAME BIRTHDAY BIRTH DEPARTMENT 李勇 Year of Birth: 1986 cs 刘晨 1987 王名 1988 ma 张立 is
二、选择表中的若干元组 1. 消除取值重复的行 1 92 2 85 3 88 90 80 在SELECT子句中使用DISTINCT短语 SC Sno Cno Grade 200215121 1 92 2 85 3 88 200215122 90 80 二、选择表中的若干元组 1. 消除取值重复的行 在SELECT子句中使用DISTINCT短语 [例6] 查询选修了课程的学生学号。 (1) SELECT Sno FROM SC; 或(默认 ALL) SELECT ALL Sno FROM SC (1)结果: 注意: DISTINCT短语的作用范围是所有目标列 例:查询选修课程的各种成绩 错误的写法 SELECT DISTINCT Cno,DISTINCT Grade FROM SC; 正确的写法 SELECT DISTINCT Cno,Grade FROM SC; (2)结果: Sno 200215121 200215122 Sno 200215121 200215122 (2) SELECT DISTINCT Sno FROM SC;
2.查询满足条件的元组 WHERE子句常用的查询条件 表3.3 常用的查询条件 查询条件 谓 词 比 较 = , > < 表3.3 常用的查询条件 查询条件 谓 词 比 较 = , > < >= <= != <> !> !< ; NOT + 上述比较运算符 确定范围 BETWEEN AND NOT BETWEEN AND 确定集合 IN NOT IN 字符匹配 LIKE NOT LIKE 空 值 IS NULL IS NOT NULL 多重条件 AND OR
(1) 比较大小 SELECT Sname FROM Student WHERE Sdept =‘CS’; =,>,<,>=,<=,!= 或 <>,!>,!<, 逻辑运算符NOT + 比较运算符 [例7] 查询 计算机科学系的全体学生的名单。 SELECT Sname FROM Student WHERE Sdept =‘CS’; [例8] 查询所有年龄在20岁以下的学生姓名及其年龄。 SELECT Sname,Sage FROM Student WHERE Sage < 20; SELECT Sname,Sage FROM Student WHERE NOT Sage >= 20; 或 [例9] 查询考试成绩有不及格的学生的学号。 SELECT DISTING Sno FROM SC WHERE Grade < 60;
(2) 确定范围 使用谓词 BETWEEN … AND … NOT BETWEEN … AND … [例10] 查询年龄在20~23岁(包括20岁和23岁)之间的学生的姓名、系别和年龄。 SELECT Sname,Sdept,Sage FROM Student WHERE Sage BETWEEN 20 AND 23; [例11] 查询年龄不在20~23岁之间的学生姓名、系别和年龄。 SELECT Sname,Sdept,Sage FROM Student WHERE Sage NOT BETWEEN 20 AND 23;
(3) 确定集合 使用谓词 IN <值表>, NOT IN <值表> <值表>:用逗号分隔的一组取值 [例12]查询信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别。 SELECT Sname,Ssex FROM Student WHERE Sdept IN ( 'IS','MA','CS' ); [例13]查询既不是信息系、数学系,也不是计算 机科学系的学生的姓名和性别。 SELECT Sname,Ssex FROM Student WHERE Sdept NOT IN ( 'IS','MA','CS' );
(4) 字符串匹配 通配符 [NOT] LIKE ‘<匹配串>’ [ESCAPE ‘ <换码字符>’] <匹配串>:指定匹配模板 匹配模板:固定字符串或含通配符的字符串 当匹配模板为固定字符串时, 可以用 = 运算符取代 LIKE 谓词 用 != 或 < >运算符取代 NOT LIKE 谓词 通配符 % (百分号) 代表任意长度(长度可以为0)的字符串 例:a%b表示以a开头,以b结尾的任意长度的字符串。如acb,addgb,ab 等都满足该匹配串 _ (下横线) 代表任意单个字符 例:a_b表示以a开头,以b结尾的长度为3的任意字符串。如acb,afb等都满足该匹配串
ESCAPE 短语: 1) 匹配模板为固定字符串 [例14] 查询学号为200215121的学生的详细情况。 SELECT * FROM Student WHERE Sno LIKE ' 200215121 '; 等价于: SELECT * WHERE Sno = ' 200215121 ';
2) 匹配模板为含通配符的字符串 [例15] 查询所有姓刘学生的姓名、学号和性别。 SELECT Sname,Sno,Ssex [例15] 查询所有姓刘学生的姓名、学号和性别。 SELECT Sname,Sno,Ssex FROM Student WHERE Sname LIKE ‘刘%’; [例16] 查询姓"欧阳"且全名为三个汉字的学生的姓名。 SELECT Sname FROM Student WHERE Sname LIKE ‘欧阳__’; [例17] 查询名字中第2个字为"阳"字的学生的姓名和学号。 SELECT Sname,Sno FROM Student WHERE Sname LIKE '__阳%';
3) 使用换码字符将通配符转义为普通字符 [例18] 查询所有不姓刘的学生姓名。 SELECT Sname,Sno,Ssex [例18] 查询所有不姓刘的学生姓名。 SELECT Sname,Sno,Ssex FROM Student WHERE Sname NOT LIKE ‘刘%’; 3) 使用换码字符将通配符转义为普通字符 [例19] 查询DB_Design课程的课程号和学分。 SELECT Cno,Ccredit FROM Course WHERE Cname LIKE 'DB\_Design' ESCAPE '\‘; [例20] 查询以"DB_"开头,且倒数第3个字符为 i的课程的详细情况。 SELECT * FROM Course WHERE Cname LIKE 'DB\_%i_ _' ESCAPE ' \ ';
(5) 涉及空值的查询 使用谓词 IS NULL 或 IS NOT NULL “IS NULL” 不能用 “= NULL” 代替 [例21] 某些学生选修课程后没有参加考试,所以有选课记录,但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号。 SELECT Sno,Cno FROM SC WHERE Grade IS NULL; [例22] 查所有有成绩的学生学号和课程号。 SELECT Sno,Cno FROM SC WHERE Grade IS NOT NULL;
(6) 多重条件查询 用逻辑运算符AND和 OR来联结多个查询条件 AND的优先级高于OR 可以用括号改变优先级 可用来实现多种其他谓词 [NOT] IN [NOT] BETWEEN … AND … [例23] 查询计算机系年龄在20岁以下的学生姓名。 SELECT Sname FROM Student WHERE Sdept= 'CS' AND Sage<20;
改写[例12] [例12] 查询信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别。 SELECT Sname,Ssex FROM Student WHERE Sdept IN ( 'IS','MA','CS' ); 可改写为: FROM Student WHERE Sdept= ' IS ' OR Sdept= ' MA' OR Sdept= ' CS ';
改写[例10] [例10] 查询年龄在20~23岁(包括20岁和23岁)之间学生的姓名、系别和年龄。 [例10] 查询年龄在20~23岁(包括20岁和23岁)之间学生的姓名、系别和年龄。 SELECT Sname,Sdept,Sage FROM Student WHERE Sage BETWEEN 20 AND 23; 可改写为: WHERE Sage>=20 AND Sage<=23;
三、对查询结果排序 92 90 88 85 使用ORDER BY子句 60 可以按一个或多个属性列排序 Sno Grade 200215126 200215129 200215121 92 200215123 90 200215125 88 200215132 85 200215131 60 三、对查询结果排序 使用ORDER BY子句 可以按一个或多个属性列排序 升序:ASC;降序:DESC;缺省值为升序 当排序列含空值时 ASC:排序列为空值的元组最后显示 DESC:排序列为空值的元组最先显示 [例24] 查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列。 SELECT Sno,Grade FROM SC WHERE Cno= ' 3 ' ORDER BY Grade DESC; [例25] 查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列。 SELECT * FROM Student ORDER BY Sdept,Sage DESC;
四、使用集函数 5类主要集函数 计数 COUNT([DISTINCT|ALL] *) 计算总和 SUM([DISTINCT|ALL] <列名>) 计算平均值 AVG([DISTINCT|ALL] <列名>) 求最大值 MAX([DISTINCT|ALL] <列名>) 求最小值 MIN([DISTINCT|ALL] <列名>) DISTINCT短语:在计算时要取消指定列中的重复值 ALL短语:不取消重复值(为缺省值)
[例26] 查询学生总人数。 SELECT COUNT(*) FROM Student; [例27] 查询选修了课程的学生人数。 SELECT COUNT(DISTINCT Sno) FROM SC; 注:用DISTINCT以避免重复计算学生人数 [例28] 计算1号课程的学生平均成绩。 SELECT AVG(Grade) FROM SC WHERE Cno= ' 1 ';
[例29] 查询选修1号课程的学生最高分数。 SELECT MAX(Grade) FROM SC WHERE Cno= ' 1 '; [例30] 查询学生200215012选修课程的总学分数。 SELECT SUM(Gcredit) FROM SC,Course WHERE Sno= ' 200215012 ' AND SC.Cno=Course.Cno;
五、对查询结果分组 使用GROUP BY子句分组,细化集函数的作用对象 未对查询结果分组,集函数将作用于整个查询结果 对查询结果分组后,集函数将分别作用于每个组 [例31] 求各个课程号及相应的选课人数。 SELECT Cno,COUNT(Sno) FROM SC GROUP BY Cno; Cno COUNT(Sno) 1 22 2 34 3 44 4 33 5 48 GROUP BY子句的作用对象是查询的中间结果表; 分组方法:按指定的一列或多列值分组,值相等的为一组; 使用GROUP BY子句后,SELECT子句的列名列表中只能出现分组属性和集函数。
使用HAVING短语筛选最终输出结果 [例32] 查询选修了3门以上课程的学生学号。 SELECT Sno FROM SC [例32] 查询选修了3门以上课程的学生学号。 SELECT Sno FROM SC GROUP BY Sno HAVING COUNT(*) >3; [补充例] 查询有3门以上课程是90分以上的学生的学号及(90分以上的)课程数 SELECT Sno, COUNT(*) FROM SC WHERE Grade>=90 GROUP BY Sno HAVING COUNT(*)>3; 只有满足HAVING短语指定条件的组才输出 HAVING短语与WHERE子句的区别:作用对象不同 WHERE子句作用于基表或视图,从中选择满足条件的元组。 HAVING短语作用于组,从中选择满足条件的组。
3.4.2 连接查询 同时涉及多个表的查询称为连接查询,用来连接两个表的条件称为连接条件或连接谓词 一般格式: 3.4.2 连接查询 同时涉及多个表的查询称为连接查询,用来连接两个表的条件称为连接条件或连接谓词 一般格式: [<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2> 比较运算符:=、>、<、>=、<=、!= 或: [<表名1>.]<列名1> BETWEEN [<表名2>.]<列名2> AND [<表名2>.] <列名3> 连接字段 连接谓词中的列名称为连接字段; 连接条件中的各连接字段类型必须是可比的,但不必是相同的。
连接操作的执行过程 嵌套循环法(NESTED-LOOP) 首先在表1中找到第一个元组,然后从头开始扫描表2,逐一查找满足连接件的元组,找到后就将表1中的第一个元组与该元组拼接起来,形成结果表中一个元组。 表2全部查找完后,再找表1中第二个元组,然后再从头开始扫描表2,逐一查找满足连接条件的元组,找到后就将表1中的第二个元组与该元组拼接起来,形成结果表中一个元组。 重复上述操作,直到表1中的全部元组都处理完毕
一、等值与非等值连接查询 等值连接 [例33] 查询每个学生及其选修课程的情况。 SELECT Student.*,SC.* [例33] 查询每个学生及其选修课程的情况。 SELECT Student.*,SC.* FROM Student,SC WHERE Student.Sno = SC.Sno; Student.Sno Sname Ssex Sage Sdept SC.Sno Cno Grade 200215121 李勇 男 20 CS 1 92 2 85 3 88 200215122 刘晨 女 19 90 80
自然连接 等值连接的一种特殊情况,把目标列中重复的属性列去掉。 [例34] 对[例33]用自然连接完成。 [例34] 对[例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 200215121 李勇 男 20 CS 1 92 2 85 3 88 200215122 刘晨 女 19 90 80 或 SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade FROM Student INNER JOIN SC ON Student.SNO=SC.SNO;
二、自身连接 一个表与其自己进行连接,称为表的自身连接 需要给表起别名以示区别 由于所有属性名都是同名属性,因此必须使用别名前缀
二、自身连接 [例35] 查询每一门课的间接先修课(即先修课的先修课) SELECT FIRST.Cno,SECOND.Cpno [例35] 查询每一门课的间接先修课(即先修课的先修课) SELECT FIRST.Cno,SECOND.Cpno FROM Course FIRST,Course SECOND WHERE FIRST.Cpno = SECOND.Cno; FIRST表(Course表) SECOND表(Course表) 查询结果 Cno Cname Cpno Ccredit 1 数据库 5 4 2 数学 3 信息系统 操作系统 6 数据结构 7 数据处理 PASCAL语言 Cno Cname Cpno Ccredit 1 数据库 5 4 2 数学 3 信息系统 操作系统 6 数据结构 7 数据处理 PASCAL语言 cno cpno 1 7 3 5 6
SELECT Student.Sno,Sname,Ssex, Sage,Sdept,Cno,Grade 三、外连接(Outer Join) 外连接与普通连接的区别 普通连接操作只输出满足连接条件的元组 外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出 Student. Sno Sname Ssex Sage Sdept Cno Grade 200215121 李勇 男 20 CS 1 92 2 85 3 88 200215122 刘晨 女 19 IS 90 80 200215123 王敏 18 MA 200215125 张立 左连接——LEFT [OUTER] JOIN ON 右连接——RIGHT [OUTER] JOIN ON 外连接——FULL [OUTER] JOIN ON [例 36] 查询每个学生及其选修课程的情况包括没有选修课程的学生----用外连接操作 SELECT Student.Sno,Sname,Ssex, Sage,Sdept,Cno,Grade FROM Student LEFT OUTER JOIN SC ON (Student.SNO=SC.SNO);
四、复合条件连接 WHERE子句中含多个连接条件时,称为复合条件连接 [例37]查询选修2号课程且成绩在90分以上的所有学生的学号、姓名 SELECT Student.Sno, student.Sname FROM Student, SC WHERE Student.Sno = SC.Sno AND /* 连接谓词*/ SC.Cno= ‘ 2 ’ AND /* 其他限定条件 */ SC.Grade > 90; /* 其他限定条件 */
六、多表连接 [例38] 查询每个学生的学号、姓名、选修的课程名及成绩。 [例38] 查询每个学生的学号、姓名、选修的课程名及成绩。 SELECT Student.Sno,Sname,Ssex,Cname,Grade FROM Student,SC,Course WHERE Student.Sno = SC.Sno and SC.Cno = Course.Cno; 或 SELECT Student.Sno,Sname, Ssex, Cname,Grade FROM Student INNER JOIN SC ON Student.Sno = SC.Sno INNER JOIN Course ON SC.Cno = Course.Cno Student. Sno Sname Ssex Cname Grade 200215121 李勇 男 数据库 92 数学 85 信息系统 88 200215122 刘晨 女 90 80
3.4.3 嵌套查询 一个SELECT-FROM-WHERE语句称为一个查询块 3.4.3 嵌套查询 一个SELECT-FROM-WHERE语句称为一个查询块 将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询称为嵌套查询 SELECT Sname 外层查询/父查询 FROM Student WHERE Sno IN (SELECT Sno 内层查询/子查询 FROM SC WHERE Cno= ' 2 '); 子查询的限制 不能使用ORDER BY子句 层层嵌套方式反映了 SQL语言的结构化 有些嵌套查询可以用连接运算替代
嵌套查询分类 不相关子查询 子查询的查询条件不依赖于父查询 相关子查询 子查询的查询条件依赖于父查询
嵌套查询求解方法 不相关子查询 是由里向外逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。 首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表; 然后再取外层表的下一个元组; 重复这一过程,直至外层表全部检查完为止。
一、带有IN谓词的子查询 Sdept IS [例39] 查询与“刘晨”在同一个系学习的学生。 此查询要求可以分步来完成 [例39] 查询与“刘晨”在同一个系学习的学生。 此查询要求可以分步来完成 结果为: ① 确定“刘晨”所在系名 SELECT Sdept FROM Student WHERE Sname= ' 刘晨 '; Sdept IS ② 查找所有在IS系学习的学生。 SELECT Sno,Sname,Sdept FROM Student WHERE Sdept= ' IS '; 结果为: Sno Sname Sdept 200215122 刘晨 IS 200215124 张立
一、带有IN谓词的子查询 [例39] 查询与“刘晨”在同一个系学习的学生。 此查询要求可以分步来完成 ① 确定“刘晨”所在系名 [例39] 查询与“刘晨”在同一个系学习的学生。 此查询要求可以分步来完成 ① 确定“刘晨”所在系名 SELECT Sdept FROM Student WHERE Sname= ' 刘晨 '; ③ 将第一步查询嵌入到第二步查询的条件中。 SELECT Sno,Sname,Sdept FROM Student WHERE Sdept IN (SELECT Sdept WHERE Sname= ‘ 刘晨 ’); ② 查找所有在IS系学习的学生。 SELECT Sno,Sname,Sdept FROM Student WHERE Sdept= ' IS '; 本例为不相关子查询
父查询和子查询中的表均可以定义别名 用自身连接完成本查询要求 SELECT S1.Sno,S1.Sname,S1.Sdept FROM Student S1,Student S2 WHERE S1.Sdept = S2.Sdept AND S2.Sname = '刘晨'; 父查询和子查询中的表均可以定义别名 SELECT Sno,Sname,Sdept FROM Student S1 WHERE S1.Sdept IN (SELECT Sdept FROM Student S2 WHERE S2.Sname= ‘ 刘晨 ’);
[例40]查询选修了课程名为“信息系统”的学生学号和姓名 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 Sno,Sname FROM Student,SC,Course WHERE Student.Sno = SC.Sno AND SC.Cno = Course.Cno AND Course.Cname=‘信息系统’; 结果: Sno Sname ------------- 200215121 李勇 200215122 刘晨
二、带有比较运算符的子查询 当能确切知道内层查询返回单值时,可用比较运算符(>,<,=,>=,<=,!=或< >)。 例:假设一个学生只可能在一个系学习,并且必须属于一个系,则在[例39]可以用 = 代替IN : SELECT Sno,Sname,Sdept FROM Student WHERE Sdept = SELECT Sdept WHERE Sname= ' 刘晨 '; 子查询一定要跟在比较符之后 错误的例子: SELECT Sno,Sname,Sdept FROM Student WHERE ( SELECT Sdept FROM Student WHERE Sname= ‘ 刘晨 ’ ) = Sdept;
[例41]找出每个学生超过他选修课程平均成绩的课程号。 SELECT Sno,Cno FROM SC x WHERE Grade>=( SELECT AVG(Grade) FROM SC y WHERE y.Sno=x.Sno ); 相关子查询 首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表; 然后再取外层表的下一个元组; 重复这一过程,直至外层表全部检查完为止。
SELECT AVG(Grade) FROM SC y WHERE y.Sno=“200215121” ); 学 号 Sno 课 程 号 Cno 成 绩 Grade 200215121 1 92 2 85 3 88 200215122 90 80 学 号 Sno 课 程 号 Cno 成 绩 Grade 200215121 1 92 2 85 3 88 200215122 90 80 取X表中的学号=200215121 SELECT AVG(Grade) FROM SC y WHERE y.Sno=“200215121” );
三、带有ANY或ALL谓词的子查询 谓词语义 ANY:任意一个值 ALL:所有值
三、带有ANY或ALL谓词的子查询 需要配合使用比较运算符 > ANY 大于子查询结果中的某个值
[例42] 查询其他系中比计算机科学系任意一个(其中某一个)学生年龄小的学生姓名和年龄 SELECT Sname,Sage [例42] 查询其他系中比计算机科学系任意一个(其中某一个)学生年龄小的学生姓名和年龄 SELECT Sname,Sage FROM Student WHERE Sage < ANY (SELECT Sage WHERE Sdept= ' CS ') AND Sdept <> ' CS ' ; /* 注意这是父查询块中的条件 */ 查询结果: Sname Sage ------------------- 王敏 18 张立 19 执行过程: 1.DBMS执行此查询时,首先处理子查询,找出CS系中所有学生的年龄,构成一个集合(18,19) 2. 处理父查询,找所有不是CS系且年龄小于18 或 19的学生
ANY和ALL谓词有时可以用集函数实现 ANY与ALL与集函数的对应关系 = <>或!= < <= > >= ANY IN -- <MAX <=MAX >MIN >= MIN ALL NOT IN <MIN <= MIN >MAX >= MAX
[例42 ']:用集函数实现[例42] SELECT Sname,Sage FROM Student WHERE Sage < 用集函数实现子查询通常比直接用ANY或ALL查询效率要高,因为前者通常能够减少比较次数 [例42 ']:用集函数实现[例42] SELECT Sname,Sage FROM Student WHERE Sage < (SELECT MAX(Sage) WHERE Sdept= ' CS ') AND Sdept <> ' CS ';
[例43] 查询其他系中比计算机科学系所有学生年龄都小的学生姓名及年龄。 [例43] 查询其他系中比计算机科学系所有学生年龄都小的学生姓名及年龄。 方法二:用集函数 SELECT Sname,Sage FROM Student WHERE Sage < (SELECT MIN(Sage) FROM Student WHERE Sdept= ' CS ') AND Sdept <>' CS ’; 方法一:用ALL谓词 SELECT Sname,Sage FROM Student WHERE Sage < ALL (SELECT Sage WHERE Sdept= ' CS ') AND Sdept <> ' CS ’; 查询结果: Sname Sage ------------------- 王敏 18
四、带有EXISTS谓词的子查询 1. EXISTS谓词--存在量词 带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”。 若内层查询结果非空,则返回真值。 若内层查询结果为空,则返回假值。 由EXISTS引出的子查询,其目标列表达式通常都用* ,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义 2. NOT EXISTS谓词
用嵌套查询 [例44] 查询所有选修了1号课程的学生姓名。 SELECT Sname 用连接运算 FROM Student [例44] 查询所有选修了1号课程的学生姓名。 用嵌套查询 SELECT Sname FROM Student WHERE EXISTS (SELECT * FROM SC /*相关子查询*/ WHERE Sno=Student.Sno AND Cno= '1'); 用连接运算 SELECT Sname FROM Student, SC WHERE Student.Sno=SC.Sno AND SC.Cno= '1'; 求解过程的思路分析: 本查询涉及Student和SC关系。 在Student中依次取每个元组的Sno值,用此值去检查SC关系。 若SC中存在这样的元组,其Sno值等于Student.Sno值,并且其Cno= '1',则取此Student.Sname送入结果关系。
相关子查询 相关查询与我们前面的不相关子查询有一个明显区别,即子查询的查询条件依赖于外层父查询的某个属性值(在本例中是依赖于Student表的Sno值),我们称这类查询为相关子查询。 求解相关子查询不能象求解不相关子查询那样,一次将子查询求解出来,然后求解父查询。 相关子查询的内层查询由于与外层查询有关,因此必须反复求值。
[例45] 查询没有选修1号课程的学生姓名。 SELECT Sname FROM Student WHERE NOT EXISTS (SELECT * FROM SC WHERE Sno = Student.Sno AND Cno='1'); 此例用连接运算难于实现
3.不同形式的查询间的替换 一些带EXISTS或NOT EXISTS谓词的子查询不能被其他形式的子查询等价替换 所有带IN谓词、比较运算符、ANY和ALL谓词的子查询都能用带EXISTS谓词的子查询等价替换。 例:[例39]查询与“刘晨”在同一个系学习的学生。可以用带EXISTS谓词的子查询替换: SELECT Sno,Sname,Sdept FROM Student S1 WHERE EXISTS SELECT * FROM Student S2 WHERE S2.Sdept = S1.Sdept AND S2.Sname = ' 刘晨 '; 由于带EXISTS量词的相关子查询只关心内层查询是否有返回值,并不需要查具体值,因此其效率并不一定低于不相关子查询,甚至有时是最高效的方法。
4. 用EXISTS/NOT EXISTS实现全称量词(难点) SQL语言中没有全称量词 (For all) 可以把带有全称量词的谓词转换为等价的带有存在量词的谓词: (x)P ≡ ( x( P)) [例46] 查询选修了全部课程的学生姓名。 SELECT Sname FROM Student WHERE NOT EXISTS SELECT * FROM Course (SELECT * FROM SC WHERE Sno= Student.Sno AND Cno= Course.Cno);
5. 用EXISTS/NOT EXISTS实现逻辑蕴函(难点) SQL语言中没有蕴函(Implication)逻辑运算 可以利用谓词演算将逻辑蕴函谓词等价转换为: p q ≡ p∨q [例47] 查询至少选修了学生200215122选修的全部课程的学生号码。 解题思路: 用逻辑蕴函表达:查询学号为x的学生,对所有的课程y,只要200215122学生选修了课程y,则x也选修了y。 形式化表示: 用P表示谓词 “学生200215122选修了课程y” 用q表示谓词 “学生x选修了课程y” 则上述查询为: (y) p q
5. 用EXISTS/NOT EXISTS实现逻辑蕴函(难点) SQL语言中没有蕴函(Implication)逻辑运算 可以利用谓词演算将逻辑蕴函谓词等价转换为: p q ≡ p∨q [例47] 查询至少选修了学生200215122选修的全部课程的学生学号。 解题思路: 用NOT EXISTS谓词表示: SELECT DISTINCT Sno FROM SC SCX WHERE NOT EXISTS (SELECT * FROM SC SCY WHERE SCY.Sno = ' 200215122 ' AND NOT EXISTS FROM SC SCZ WHERE SCZ.Sno=SCX.Sno AND SCZ.Cno=SCY.Cno)); 等价变换: (y)p q ≡ (y ((p q )) ≡ (y (( p∨ q) ≡ y(p∧q) 变换后语义:不存在这样的课程y,学生200215122选修了y,而学生x没有选。
3.3.5 集合查询 标准SQL直接支持的集合操作种类 并操作(UNION) 一般商用数据库支持的集合操作种类 交操作(INTERSECT) 3.3.5 集合查询 标准SQL直接支持的集合操作种类 并操作(UNION) 一般商用数据库支持的集合操作种类 交操作(INTERSECT) 差操作(MINUS)
1.并操作 形式 <查询块> UNION <查询块> 形式 <查询块> UNION <查询块> 参加UNION操作的各结果表的列数必须相同;对应项的数据类型也必须相同。 [例48] 查询计算机科学系的学生或年龄不大于19岁的学生。 方法一: SELECT * FROM Student WHERE Sdept= 'CS' UNION WHERE Sage<=19; 方法二: SELECT DISTINCT * FROM Student WHERE Sdept= ‘CS’ OR Sage<=19;
[例49] 查询选修了课程1或者选修了课程2的学生。 方法一: SELECT Sno FROM SC WHERE Cno=' 1 ' UNION WHERE Cno= ' 2 '; 方法二: SELECT DISTINCT Sno FROM SC WHERE Cno=' 1 ' OR Cno= ' 2 ';
2.交操作 标准SQL中没有提供集合交操作,但可用其他方法间接实现。 [例50] 查询计算机科学系的学生与年龄不大于19岁的学生的交集. [例50] 查询计算机科学系的学生与年龄不大于19岁的学生的交集. SELECT * FROM Student WHERE Sdept= ‘CS’ INTERSECT WHERE Sage<=19; SELECT * FROM Student WHERE Sdept= 'CS' AND Sage<=19; 本例实际上就是查询计算机科学系中年龄不大于19岁的学生。
[例51] 查询选修课程1的学生集合与选修课程2的学生集合的交集。 SELECT Sno FROM SC WHERE Cno=‘1’ INTERSECT WHERE Cno=‘2’; SELECT Sno FROM SC WHERE Cno=' 1 ' AND Sno IN (SELECT Sno WHERE Cno=' 2 '); 本例实际上是查询既选修了课程1又选修了课程2的学生。
3.差操作 标准SQL中没有提供集合差操作,但可用其他方法间接实现。 [例52] 查询计算机科学系的学生与年龄不大于19岁的学生的差集。 [例52] 查询计算机科学系的学生与年龄不大于19岁的学生的差集。 SELECT * FROM Student WHERE Sdept= ‘CS’ EXCEPT WHERE Sage<=19; SELECT * FROM Student WHERE Sdept= 'CS' AND Sage>19; 本例实际上是查询计算机科学系中年龄大于19岁的学生。
3.3.6 SELECT语句的一般格式 SELECT [ALL|DISTINCT] [TOP n [ PERCENT ]] <目标列表达式> [别名] [ ,<目标列表达式> [别名]] … [INTO <表名>] FROM <表名或视图名> [别名] [ ,<表名或视图名> [别名]] … [WHERE <条件表达式>] [GROUP BY <列名1> [HAVING <条件表达式>]] [ORDER BY <列名2> [ASC|DESC]
1、目标列表达式 2、集函数格式 (1) * (2) [ <表名>.] * (4) COUNT ([DISTINCT|ALL] *) (4)[<表名>.]<属性列名表达式>[,[<表名>.]<属性列名表达式>] … <属性列名表达式>:由属性列、作用于属性列的集函数和常量的任意算术运算(+,-,*,/)组成的运算公式。 2、集函数格式 COUNT SUM AVG ([DISTINCT|ALL] <列名>) MAX MIN
3、WHERE子句条件表达式格式 (1) <属性列名> <属性列名> θ <常量> <属性列名> θ <常量> [ANY|ALL] (SELECT语句) <属性列名> <属性列名> <属性列名> [NOT] BETWEEN <常量> AND <常量> (SELECT语句) (SELECT语句) (2) <属性列名> [NOT] IN (SELECT语句) (<值1>[,<值2> ] …) (3)
(4) <属性列名> [NOT] LIKE <匹配串> (5) <属性列名> IS [NOT] NULL (6) [NOT] EXISTS (SELECT语句) AND OR <条件表达式> <条件表达> … (7)
3.5 数 据 更 新 3.5.1 插入数据 两种插入数据方式 插入单个元组 插入子查询结果
3.5 数 据 更 新 3.5.1 插入数据 一、插入单个元组 语句格式 3.5 数 据 更 新 3.5.1 插入数据 一、插入单个元组 语句格式 INSERT INTO <表名> [(<属性列1>[,<属性列2 >…)] VALUES (<常量1> [,<常量2>] … ) 功能: 将新元组插入指定表中。 INTO子句 指定要插入数据的表名及属性列 属性列的顺序可与表定义中的顺序不一致 没有指定属性列:表示要插入的是一条完整的元组,且属性列属性与表定义中的顺序一致 指定部分属性列:插入的元组在其余属性列上取空值 VALUES子句 提供的值必须与INTO子句匹配 值的个数 值的类型
[例1] 将一个新学生记录:(学号:200215128;姓名:陈冬;性别:男;所在系:IS;年龄:18岁)插入到Student表中。 INSERT INTO Student VALUES (' 200215128 ','陈冬','男','IS',18); [例2] 将学生张成民的信息插入Student表中。 INSERT INTO Student VALUES (‘ 200215126 ’,‘张成民’,‘男’,‘CS‘,19); [例3] 插入一条选课记录( ‘200215128','1 ')。 INSERT INTO SC(Sno,Cno) VALUES (' 200215128 ',' 1 '); 新插入的记录在Grade列上取空值
二、插入子查询结果 语句格式 INSERT INTO <表名> [(<属性列1> [,<属性列2>… )] 子查询; 功能:将子查询结果插入指定表中 [例4] 对每一个系,求学生的平均年龄,并把结果存入数据库。 第一步:建表 CREATE TABLE Deptage (Sdept CHAR(15) /* 系名*/ Avgage SMALLINT); /*学生平均年龄*/ 第二步:插入数据 INSERT INTO Deptage(Sdept,Avgage) SELECT Sdept,AVG(Sage) FROM Student GROUP BY Sdept;
二、插入子查询结果 语句格式 INSERT INTO <表名> [(<属性列1> [,<属性列2>… )] 子查询; 功能:将子查询结果插入指定表中 INTO子句(与插入单条元组类似) 指定要插入数据的表名及属性列 属性列的顺序可与表定义中的顺序不一致 没有指定属性列:表示要插入的是一条完整的元组 指定部分属性列:插入的元组在其余属性列上取空值 子查询 SELECT子句目标列必须与INTO子句匹配 值的个数 值的类型
3.5.2 修改数据 语句格式 UPDATE <表名> 3.5.2 修改数据 语句格式 UPDATE <表名> SET <列名>=<表达式>[,<列名>=<表达式>]… [WHERE <条件>]; 功能:修改指定表中满足WHERE子句条件的元组 SET子句:指定修改方式、要修改的列、 修改后取值。 WHERE子句:指定要修改的元组、缺省表示要修改表中的所有元组 三种修改方式 修改某一个元组的值 修改多个元组的值 带子查询的修改语句
[例5] 将学生200215121的年龄改为22岁。 UPDATE Student SET Sage=22 WHERE Sno=' 200215121 '; [例6] 将所有学生的年龄增加1岁。 UPDATE Student SET Sage= Sage+1; [例6`] 将信息系所有学生的年龄增加1岁。 UPDATE Student SET Sage= Sage+1 WHERE Sdept=' IS '; [例7] 将计算机科学系全体学生的成绩置零。 UPDATE SC SET Grade=0 WHERE 'CS'= (SELETE Sdept FROM Student WHERE Student.Sno = SC.Sno);
3.5.3 删除数据 语句格式 DELETE FROM <表名> [WHERE <条件>]; 3.5.3 删除数据 语句格式 DELETE FROM <表名> [WHERE <条件>]; 功能:删除指定表中满足WHERE子句条件的元组。 WHERE子句 指定要删除的元组 缺省表示要修改表中的所有元组 三种删除方式 删除某一个元组的值 删除多个元组的值 带子查询的删除语句
[例8] 删除学号为20021528的学生记录。 DELETE FROM Student WHERE Sno=‘200215128'; [例9] 删除所有的学生选课记录。 DELETE FROM SC; [例10] 删除计算机科学系所有学生的选课记录。 DELETE FROM SC WHERE 'CS'= (SELETE Sdept FROM Student WHERE Student.Sno=SC.Sno); [例9`] 删除2号课程的所有选课记录。 DELETE FROM SC; WHERE Cno='2';
DBMS在执行删除语句时会检查所插元组是否破坏表上已定义的完整性规则: 参照完整性 不允许删除 级联删除 DBMS在执行修改语句、插入语句时会检查修改操作是否破坏表上已定义的完整性规则: 实体完整性 主码不允许修改 用户定义的完整性 NOT NULL约束 UNIQUE约束 值域约束
更新数据与数据一致性 DBMS在执行插入、删除、更新语句时必须保证数据库一致性 必须有事务的概念和原子性 完整性检查和保证
3.6 视 图 视图的特点: 虚表,是从一个或几个基本表(或视图)导出的表 只存放视图的定义,不会出现数据冗余 3.6 视 图 视图的特点: 虚表,是从一个或几个基本表(或视图)导出的表 只存放视图的定义,不会出现数据冗余 基表中的数据发生变化,从视图中查询出的数据也随之改变 基于视图的操作 查询 删除 受限更新 基于该视图的新视图 仓库号 城市 面积 仓库号 职工号 工资 仓库号 面积 基本表 视图 仓库号 城市 职工号 工资
3.6.1 定义视图 一、 建立视图 语句格式 CREATE VIEW 3.6.1 定义视图 一、 建立视图 语句格式 CREATE VIEW <视图名> [(<列名> [,<列名>]…)] AS <子查询> [WITH CHECK OPTION]; 其中: (<列名> [,<列名>]…)为可选项,省略时,视图的列名由子查询的结果决定。 在子查询中不许使用ORDER BY 子句和DISTINCT短语 WITH CHECK OPTION 通过视图进行增删改操作时,不得破坏视图定义中的谓词条件(即子查询中的条件表达式)
组成视图的属性列名 全部省略或全部指定 省略: 由子查询中SELECT目标列中的诸字段组成 明确指定视图的所有列名: (1) 某个目标列是集函数或列表达式 (2) 目标列为 * (3) 多表连接时选出了几个同名列作为视图的字段 (4) 需要在视图中为某个列启用新的更合适的名字 DBMS执行CREATE VIEW语句时只是把视图的定义存入数据字典,并不执行其中的SELECT语句。 在对视图查询时,按视图的定义从基本表中将数据查出。
行列子集视图 从单个基本表导出只是去掉了基本表的某些行和某些列保留了码。 [例1] 建立信息系学生的视图。 [例1] 建立信息系学生的视图。 CREATE VIEW IS_Student AS SELECT Sno,Sname,Sage FROM Student WHERE Sdept= 'IS'; [例2] 建立信息系学生的视图,并要求透过该视图进行的更新操作只涉及信息系学生。 CREATE VIEW IS_Student AS SELECT Sno,Sname,Sage FROM Student WHERE Sdept= 'IS' WITH CHECK OPTION; 修改、删除操作: DBMS自动加上Sdept= 'IS'的条件 插入操作:DBMS自动检查Sdept属性值是否为'IS' 如果不是,则拒绝该插入操作 如果没有提供Sdept属性值,则自动定义Sdept为'IS'
基于多个基表的视图 [例3] 建立信息系选修了1号课程的学生视图。 CREATE VIEW IS_S1(Sno,Sname,Grade) [例3] 建立信息系选修了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';
基于视图的视图 带表达式的视图 [例4] 建立信息系选修了1号课程且成绩在90分以上的学生的视图。 CREATE VIEW IS_S2 AS [例4] 建立信息系选修了1号课程且成绩在90分以上的学生的视图。 CREATE VIEW IS_S2 AS SELECT Sno,Sname,Grade FROM IS_S1 WHERE Grade>=90; 带表达式的视图 [例5] 定义一个反映学生出生年份的视图。 CREATE VIEW BT_S (Sno,Sname,Sbirth) AS SELECT Sno,Sname,2004-Sage FROM Student; 设置一些派生属性列, 也称为虚拟列--Sbirth ; 带表达式的视图必须明确定义组成视图的各个属性列名。
建立分组视图 [例6] 将学生的学号及他的平均成绩定义为一个视图。假设SC表中“成绩”列Grade为数字型。 CREAT VIEW S_G (Sno,Gavg) AS SELECT Sno,AVG(Grade) FROM SC GROUP BY Sno;
一类不易扩充的视图 以 SELECT * 方式创建的视图可扩充性差,应尽可能避免。 [例 7 ]将Student表中所有女生记录定义为一个视图。 CREATE VIEW F_Student1(stdnum,name,sex,age,dept) AS SELECT * FROM Student WHERE Ssex='女'; CREATE VIEW F_Student2 (stdnum,name,sex,age,dept) AS SELECT Sno,Sname,Ssex,Sage,Sdept FROM Student WHERE Ssex=‘女’; 为基表Student增加属性列不会破坏Student表与F_Student2视图的映象关系。 缺点:修改基表Student的结构后,Student表与F_Student1视图的映象关系被破坏,导致该视图不能正确工作。
常见的视图形式 行列子集视图 WITH CHECK OPTION的视图 基于多个基表的视图 基于视图的视图 带表达式的视图 分组视图
DROP VIEW <视图名>; 说明: 二、 删除视图 语句格式: DROP VIEW <视图名>; 说明: 该语句从数据字典中删除指定的视图定义; 由该视图导出的其他视图定义仍在数据字典中,但已不能使用,必须显式删除; 删除基表时,由该基表导出的所有视图定义都必须显式删除。 [例8] 删除视图IS_S1 DROP VIEW IS_S1;
3.6.2 查询视图 从用户角度:查询视图与查询基本表相同 DBMS实现视图查询的方法 3.6.2 查询视图 从用户角度:查询视图与查询基本表相同 DBMS实现视图查询的方法 实体化视图(View Materialization) 有效性检查:检查所查询的视图是否存在 执行视图定义,将视图临时实体化,生成临时表 查询视图转换为查询临时表 查询完毕删除被实体化的视图(临时表) 视图消解法(View Resolution) 进行有效性检查,检查查询的表、视图等是否存在。如果存在,则从数据字典中取出视图的定义。 把视图定义中的子查询与用户的查询结合起来,转换成等价的对基本表的查询。 执行修正后的查询。
[例9] 在信息系学生的视图中找出年龄小于20岁的学生。 SELECT Sno,Sage FROM IS_Student WHERE Sage<20; IS_Student视图的定义 (视图定义例1): CREATE VIEW IS_Student AS SELECT Sno,Sname,Sage FROM Student WHERE Sdept= 'IS‘; 用视图消解法,转换后的查询语句为: SELECT Sno,Sage FROM Student WHERE Sdept= 'IS' AND Sage<20;
[例10] 查询信息系选修了1号课程的学生 SELECT Sno,Sname FROM IS_Student,SC WHERE IS_Student.Sno =SC.Sno AND SC.Cno= '1'; 用视图消解法,转换后的查询语句为: SELECT Sno,Sage FROM Student,SC WHERE Sdept= 'IS' AND Student.Sno =SC.Sno AND SC.Cno= '1'; ;
视图消解法的局限 有些情况下,视图消解法不能生成正确查询。采用视图消解法的DBMS会限制这类查询。 [例11]在S_G视图中查询平均成绩在90分以上的学生学号和平均成绩 SELECT * FROM S_G WHERE Gavg>=90; S_G视图定义: CREATE VIEW S_G (Sno,Gavg) AS SELECT Sno,AVG(Grade) FROM SC GROUP BY Sno; 查询转换 错误: SELECT Sno,AVG(Grade) FROM SC WHERE AVG(Grade)>=90 GROUP BY Sno; 正确: SELECT Sno,AVG(Grade) FROM SC GROUP BY Sno HAVING AVG(Grade)>=90;
3.5.3 更新视图 用户角度:更新视图与更新基本表相同 DBMS实现视图更新的方法 3.5.3 更新视图 用户角度:更新视图与更新基本表相同 DBMS实现视图更新的方法 视图实体化法(View Materialization) 视图消解法(View Resolution) 指定WITH CHECK OPTION子句后 DBMS在更新视图时会进行检查,防止用户通过视图对不属于视图范围内的基本表数据进行更新。 [例12] 将信息系学生视图IS_Student中学号200215122的学生姓名改为“刘辰”。 UPDATE IS_Student SET Sname= '刘辰' WHERE Sno= ' 200215122 '; 转换后的语句: UPDATE Student SET Sname= '刘辰' WHERE Sno= ' 200215122 ' AND Sdept= 'IS';
[例13] 向信息系学生视图IS_S中插入一个新的学生记录: 200215129,赵新,20岁。 INSERT INTO IS_Student VALUES(‘200215129’,‘赵新’,20); 转换为对基本表的更新: INTO Student(Sno,Sname,Sage,Sdept) VALUES(‘200215129','赵新',20,'IS' );
[例14] 删除视图IS_S中学号为200215129的记录 DELETE FROM IS_Student WHERE Sno= ‘200215129'; 转换为对基本表的更新: FROM Student WHERE Sno= ‘200215129' AND Sdept= 'IS';
更新视图的限制 一些视图是不可更新的,因为对这些视图的更新不能唯一地有意义地转换成对相应基本表的更新(对两类方法均如此) 例: [例11]中的视图S_G为不可更新视图。 CREATE VIEW S_G (Sno,Gavg) AS SELECT Sno,AVG(Grade) FROM SC GROUP BY Sno; 对于如下更新语句: UPDATE S_G SET Gavg=90 WHERE Sno= ' 200215129 '; 无论实体化法还是消解法都无法将其转换成对基本表SC的更新。
实际系统对视图更新的限制 允许对行列子集视图进行更新 对其他类型视图的更新不同系统有不同限制 DB2对视图更新的限制: (1) 若视图是由两个以上基本表导出的,则此视图不允许更新。 (2) 若视图的字段来自字段表达式或常数,则不允许对此视图执行INSERT和UPDATE操作,但允许执行DELETE 操作。 (3) 若视图的字段来自集函数,则此视图不允许更新。 (4) 若视图定义中含有GROUP BY子句,则此视图不允许更新。 (5) 若视图定义中含有DISTINCT短语,则此视图不允许更新。 (6) 若视图定义中有嵌套查询,并且内层查询的FROM子句中涉及的表也是导出该视图的基本表,则此视图不允许更新。 (7) 一个不允许更新的视图上定义的视图也不允许更新
例:视图GOOD_SC(修课成绩在平均成绩之上的元组) CREATE VIEW GOOD_SC AS SELECT Sno,Cno,Grade FROM SC WHERE Grade > (SELECT AVG(Grade) FROM SC); 内层查询的FROM子句中涉及的表也是导出该视图的基本表,则此视图不允许更新。
3.6.4 视图的作用 视图能够简化用户的操作 视图使用户能以多种角度看待同一数据 3.6.4 视图的作用 视图能够简化用户的操作 当视图中数据不是直接来自基本表时,定义视图能够简化用户的操作 基于多张表连接形成的视图 基于复杂嵌套查询的视图 含导出属性的视图 视图使用户能以多种角度看待同一数据 视图机制能使不同用户以不同方式看待同一数据,适应数据库共享的需要
视图对重构数据库提供了一定程度的逻辑独立性 例:数据库逻辑结构发生改变 学生关系Student(Sno,Sname,Ssex,Sage,Sdept) “垂直”地分成两个基本表: SX(Sno,Sname,Sage) SY(Sno,Ssex,Sdept) 物理独立性与逻辑独立性的概念 视图在一定程度上保证了数据的逻辑独立性 视图只能在一定程度上提供数据的逻辑独立性 由于对视图的更新是有条件的,因此应用程序中修改数据的语句可能仍会因基本表结构的改变而改变。 通过建立一个视图Student: CREATE VIEW Student(Sno,Sname,Ssex,Sage,Sdept) AS SELECT SX.Sno,SX.Sname,SY.Ssex,SX.Sage,SY.Sdept FROM SX,SY WHERE SX.Sno=SY.Sno; 使用户的外模式保持不变,从而对原Student表的查询程序不必修改。
对不同用户定义不同视图,使每个用户只能看到他有权看到的数据 通过WITH CHECK OPTION对关键数据定义操作时间限制 视图能够对机密数据提供安全保护 对不同用户定义不同视图,使每个用户只能看到他有权看到的数据 通过WITH CHECK OPTION对关键数据定义操作时间限制 适当的利用视图可以更清晰的表达查询 例如:查询每个同学最高成绩的课程号。 第一步:先定义一个视图,求出每个同学的最高成绩: CREATE VIEW VMGRADE AS SELECT SNO,MAX(Grade) Mgrade FROM SC GROUP BY Sno; 第二步:用如下的查询语句完成查询。 SELECT SC.Sno,Cno FROM SC,VMGRADE WHERE SC.Sno= VMGRADE.Sno AND SC.GRADE= VMGRADE. Mgrade;
第三章作业题: 第127页习题第3、4、5、6、7、8题