关系数据库标准语言 SQL
SQL 概述
SQL 的产生与发展
SQL 标准从公布以来随数据库技术的发展而不断发展、不断丰富。
但目前没有一个数据库系统能够支持 SQL 标准的所有概念和特性。
同时,许多软件厂商对 SQL 基本命令集还进行了不同程度的扩充和修改,又可以支持标准以外的一些功能特性。
SQL 功能组成
- DDL(Schema Data Definition Language):模式数据定义语言——数据定义的功能。
- 外(子)模式 DDL(Subschema Data Definition Language):外模式数据定义语言。
- DML(Data Manipulation Language):数据操纵语言——数据查询、数据更新功能。
- DCL(Data Control Language):数据控制语言——数据控制功能。
SQL 的特点
SQL 是一个综合的、功能极强同时又简洁易学的语言。SQL 集数据查询(data query)、数据操纵(data manipulation)、数据定义(data definition)和数据控制(data control)功能于一体。其特点如下:
综合统一 集 DDL、DML、DCL 于一体,语言风格同意,可以独立完成数据库生命周期中的全部活动:
- 定义关系模式、插入数据、建立数据库;
- 对数据库的数据进行查询和更新;
- 数据库的重构和维护;
- 数据库安全性、完整性控制。
高度非过程化
- 过程化:做什么+怎么做
- 非过程化:做什么
面向集合的操作方式
- 操作对象、操作结果均为数据记录的集合。
以同一种语法结构提供多种使用方式
- 独立语言:独立地用于联机交互地使用方式;
- 嵌入式语言:可以嵌入高级语言中。
语言简洁,易学易用:核心功能只用了下表中的 9 个动词。
SQL 功能 | 动词 |
---|---|
数据查询 | SELECT |
数据定义 | CREATE、DROP、ALTER |
数据操纵 | INSERT、UPDATE、DELETE |
数据控制 | GRANT、REVOKE |
SQL 基本概念
支持 SQL 的关系数据库管理系统同样支持关系数据库三级模式的结构。
模式包括若干基本表,外模式包含若干视图和部分基本表,而内模式包括若干存储文件。SQL 模式是基本表和约束的集合;而关系可以是基本表,也可以是视图,在逻辑概念上他们是等同的;基本表是物理上独立存在的表,视图则是虚表,是逻辑概念上的表。
数据定义
一个关系数据库管理系统的实例中可以建立多个数据库,一个数据库中可以建立多个模式,一个模式下通常包括多个表、视图和索引等数据库对象。
SQL 的数据定义语句 | |||
操作对象 | 操作方式 | ||
创建 | 删除 | 修改 | |
模式 | CREATE SCHEMA | DROP SCHEMA | |
表 | CREATE TABLE | DROP TABLE | ALTER TABLE |
视图 | CREATE VIEW | DROP VIEW | |
索引 | CREATE INDEX | DROP INDEX | ALTER INDEX |
模式的定义与删除
定义模式
在 SQL 中,定义模式的语句如下:
CREATE SCHEMA <模式名> AUTHORIZATION <用户名>;
如果没有指定 <模式名>,那么 <模式名> 隐含为 <用户名>。
例:为用户WANG定义一个学生-课程模式S-T。
CREATE SCHEMA "S-T" AUTHORIZATION WANG;
CREATE SCHEMA AUTHORIZATION WANG;
该语句没有指定<模式名>,所以模式名隐含为用户名WANG。
定义模式实际上定义了一个命名空间,在这个空间中可以进一步定义该模式包含的数据库对象,例如基本表、视图、索引等。
所以用户可以在创建模式的同时在这个模式定义中进一步创建基本表、视图、定义授权。
CREATE SCHEMA <模式名> AUTHORIZATION <用户名> [<表定义子句>|<视图定义子句>|<授权定义子句>];
例:为用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)
);
删除模式
在 SQL 中,删除模式的语句如下:
DROP SCHEMA <模式名> <CASCADE|RESTRICT>;
其中,CASCADE 和 RESTRICT 两者必选其一。
选择了 CASCADE(级联),表示在删除模式的同时把该模式中所有的数据库对象全部删除;
选择了 RESTRICT(限制),表示如果该模式中已经定义了下属的数据库对象(如表、视图等),则拒绝删除该语句的执行。
DROP SCHEMA ZHANG CASCADE;
该语句删除了模式ZHANG,同时,该模式中定义的表TAB1也被删除了。
基本表的定义、删除与修改
定义基本表
创建模式就是建立一个数据库的命名空间,在这个空间中首先要定义的是该模式包含的数据库基本表。
SQL 定义基本表的语句如下:
CREATE TABLE <表名>
(<列名><数据类型>[列级完整约束条件]
[,<列名><数据类型>[列级完整约束条件]]
···
[,<表级完整性约束条件>]);
例:建立一个“学生”表Student。
CREATE TABLE Student
(Sno CHAR(9) PRIMARY KEY, /*列级完整性约束条件,Sno是主码*/
Sname CHAR(20) UNIQUE, /*Sname取唯一值*/
Ssex CHAR(2),
Sage SMALLINT,
Sdept CHAR(20),
);
执行该语句后,就会在数据库中建立一个新的空“学生”表Student,并将有关“学生”表的定义及有关约束条件存放在数据字典中。
例:建立一个“课程”表Course。
CREATE TABLE Course
(Cno CHAR(4) PRIMARY KEY, /*列级完整性约束条件,Cno是主码*/
Cname CHAR(40) NOT NULL, /*列级完整性约束条件,Cname不能取空值*/
Cpno CHAR(4), /*Cpno的含义是先修课*/
Ccredit SMALLINT,
FOREIGN KEY(Cpno) REFERENCES Course(Cno),
/*表级完整性约束,Cpno是外码,被参照表是Course,被参照列是Cno*/
);
本例中参照表和被参照表可以是同一个表。
例:建立学生选课表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*/
)
数据类型
在 SQL 中,域的概念用数据类型来实现。
数据类型 | 含义 |
---|---|
CHAR(n),CHARACTER(n) | 长度为 n 的定长字符串 |
VARCHER(n),CHARACTERVARYING(n) | 最大长度为 n 的变长字符串 |
CLOB | 字符串大对象 |
BLOB | 二进制大对象 |
INT,INTEGER | 长整数(4 字节) |
SMALLINT | 短整数(2 字节) |
BIGINT | 大整数(8 字节) |
NUMERIC(p, d) | 定点数,由 p 位数字(不包括符号、小数点)组成,小数点后面有 d 位数字 |
DECIMAL(p, d),DEC(p, d) | 同 NUMERIC |
REAL | 取决于机器精度的单精度浮点数 |
DOUBLE PRECISION | 取决于机器精度的双精度浮点数 |
FLOAT(n) | 可选精度的浮点数,精度至少为 n 位数字 |
BOOLEAN | 逻辑布尔量 |
DATE | 日期,包含年、月、日,格式为 YYYY-MM-DD |
TIME | 时间,包含一日的时、分、秒,格式为 HH: MM: SS |
TIMESTAMP | 时间戳类型 |
INTERVAL | 时间间隔类型 |
需要注意的是,不同的关系数据库管理系统中支持的数据类型不完全相同。
模式与表
每一个基本表都属于某一个模式,一个模式包含多个基本表。
定义基本表时一般有三种方法定义它的所属模式。
方法一,在表明中明显地给出模式名。
CREATE TABLE "S-T".Student(···); /*Student所属的模式是S-T*/
CREATE TABLE "S-T".Course(···); /*Course所属的模式是S-T*/
CREATE TABLE "S-T".SC(···); /*SC所属的模式是S-T*/
方法二,在创建模式语句中同时创建表。
方法三,设置所属的模式,这样在创建表时表名中不必给出模式名。
当用户创建基本表(或其他数据库对象)时若没有指定模式,系统根据搜索路径(search path)来确定该对象所属的模式。
搜索路径包含一组模式列表,关系数据库管理系统会使用模式列表中第一个存在的模式作为数据库对象的模式名。
若搜索路径中的模式名都不存在,系统将给出错误。
一般使用
SHOW search_path;
来显示当前的搜索路径。
搜索路径的当前默认值是$user,PUBLIC。其喊一声首先搜索与用户名相同的模式名,如果该模式名不存在,则使用PUBLIC模式。
数据库管理员也可以设置搜索路径,例如:
SET search_path TO "S-T",PUBLIC;
然后,定义基本表:
CREATE TABLE Student(···);
结果就是建立了S-T.Student基本表。
修改基本表
SQL 修改基本表的语句如下:
ALTER TABLE <表名>
[ADD [COLUMN]<新列名><数据类型>[完整性约束]]
[ADD <表级完整约束>]
[DROP [COLUMN]<列名>[CASCADE|RESTRICT]]
[DROP CONSTRAINT<完整性约束名>[CASCADE|RESTRICT]]
[ALTER COLUMN <列名><数据类型>];
其中 <表名> 是要修改的基本表,ADD 子句用于增加新列、新的列级完整性约束条件和新的表级完整性约束条件。
DROP COLUMN 子句用于删除表中的列,如果指定了 CASCADE 短语,则自动删除引用了该列的其他对象;如果指定了 RESTRICT 短语,则如果该列被其他对象引用,RDBMS 将拒绝删除该列。
DROP CONSTRAINT 子句用于删除指定的完整性约束条件。
ALTER COLUMN 子句用于修改原有的列定义,包括修改列名和数据类型。
例:向Student表增加“入学时间”列,其数据类型为日期型。
ALTER TABLE Student ADD S_entrance DATE;
例:将年龄的数据类型由字符型(假设原来的数据类型是字符型)改为整数。
ALTER TABLE Student ALTER COLUMN Sage INT;
例:增加课程名称必须取唯一值的约束条件。
ALTER TABLE Course ADD UNIQUE(Cname);
删除基本表
SQL 删除基本表的语句如下:
DROP TABLE <表名> [RESTRICT|CASCADE];
选择 RESTRICT,如果存在依赖该表的对象(其他表的约束(如 CHECK,FOREIGN KEY 等约束)、视图、触发器(trigger)、存储过程或函数),那么该表不能被删除;
选择 CASCADE,则该表没有删除限制,在删除该表的同时,相关的依赖对象将被一起被删除。
在默认情况下,选择的是 RESTRICT。
例:删除Student表。
DROP TABLE Student CASCADE;
在本例中,SC表通过外码Sno引用了Student,那么在执行该操作后,Student表被删除的同时,SC表也会被级联删除。
例:若上表建有视图,选择RESTRICT时表不能删除;选择CASCADE时可以删除表,视图也会被自动删除。
CREATE VIEW IS_Student /*Student表上建立视图*/
AS
SELECT Sno,Sname,Sage
FROM Student
WHERE Sdept='IS';
DROP TABLE Student RESTRICT; /*删除Student表*/
——ERROR:cannot drop table Student because other objects depend on it
/*系统返回错误信息,存在依赖该表的对象,此表不能被删除*/
DROP TABLE Student CASCADE; /*删除Student表*/
——NOTICE:drop cascades to view IS_Student
/*系统返回提示,此表上的视图也被删除*/
SELECT * FROM IS_Student;
——ERROR:relation "IS_Student" does not exist
注:不同数据库产品在遵循SQL标准的基础上具体实现细节和处理策略会与标准略有差别。
索引的建立与删除
当表的数据量比较大时,查询操作会比较耗时,建立索引可以加快查询的速度。
建立索引
SQL 建立索引的语句如下:
CREATE [UNIQUE] [CLUSTER] INDEX <索引名>
ON <表名>(<列名>[<次序>][,<列名>[<次序>]]···);
其中对的 <表名> 是要建立索引的基本表的名字。
索引可以建立在该表的一列或多列上,各列名之间用逗号分隔。
每个 <列名> 后面还可以用 <次序> 指定索引值的排列次序,可选 ASC(升序)或 DESC(降序),默认值为 ASC。
UNIQUE 表明此索引的每一个索引值只对应唯一的数据记录。
CLUSTER 表示要建立的索引是聚簇索引。
例:为学生-课程数据库中的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);
修改索引
SQL 修改索引的语句如下:
ALTER INDEX <旧索引名> REMANE TO <新索引名>; /*对已建立的索引重新命名*/
例:将SC表的SCno索引名改为SCSno。
ALTER INDEX SCno REMANE TO SCSno;
删除索引
SQL 删除索引的语句如下:
DROP INDEX <索引名>;
例:删除Student表的Stusname索引。
DROP INDEX <Stusname>;
删除索引时,系统会同时从数据字典中删去有关该索引的描述。
数据字典
数据字典是关系数据库管理系统内部的一组系统表,它记录了数据库中所有的定义信息,包括关系模式的定义、视图定义、索引定义、完整性约束定义、各类用户对数据库的操作权限、统计信息等。关系数据库管理系统在执行 SQL 的数据定义语句时,实际上就是在更新数据字典表中的相应信息。在进行查询优化和查询处理时,数据字典中的信息是其重要依据。
数据查询
数据查询是数据库的核心操作。SQL 提供了 SELECT 语句进行数据查询,一般格式为:
SELECT [ALL|DISTINCT]<目标列表达式>[,<目标列表达式>]···
FROM <表名或视图名>[,<表名或视图名>···]|(<SELECT语句>)[AS]<别名>
[WHERE <条件表达式>]
[GROUP BY <别名1>[HAVING <条件表达式>]]
[ORDER BY <别名2>[ASC|DESC]];
单表查询
选择表中的若干列
查询指定列
例:查询全体学生的学号与姓名。
SELECT Sno,Sname
FROM Student;
例:查询全体学生的姓名、学号、所在系。
SELECT Sname,Sno,Sdept
FROM Student;
查询全部列
例:查询全体学生的详细记录。
SELECT *
FROM Student;
等价于
SELECT Sno,Sname,Ssex,Sage,Sdept
FROM Student;
查询经过计算的值
例:查询全体学生的姓名及其出生年份。
SELECT Sname,2024-Sage /*查询结果的第2列是一个算术表达式*/
FROM Student;
例:查询全体学生的姓名、出生年份和所在的院系,要求用小写字母表示系名。
SELECT Sname,'Year of Birth:',2024-Sage,LOWER(Sdept)
FROM Student;
用户可以通过指定别名来改变查询结果的列标题,这对于含算术表达式、常量、函数名的目标列表达式尤为有用。
例:将上例中的表达式用别名表示。
SELECT Sname NAME,'Year of Birth:' BIRTH,2024-Sage BIRTHDAY,LOWER(Sdept) DEPARTMENT
FROM Student;
选择表中的若干元组
取消取值重复的行
两个本来不完全相同的元组在投影到指定的某些列上后,可能会变成相同的行。可以用 DISTINCT 消除它们。
例:查询选修了课程的学生学号。
SELECT Sno
FROM SC;
等价于
SELECT ALL Sno
FROM SC;
该查询结果包含了许多重复的行,如果去掉结果表中的重复行,必须指定DISTINCT:
SELECT DISTINCT Sno
FROM SC;
查询满足条件的元组
查询满足指定条件的元组可以通过 WHERE 子句实现。
查询条件 | 谓词 |
---|---|
比较 | =,>,<,> =,<=,!=,<>,! <,!>;NOT+上述比较运算符 |
确定范围 | BETWEEN AND,NOT BETWEEN AND |
确定集合 | IN,NOT IN |
字符匹配 | LIKE,NOT LIKE |
空值 | IS NULL,IS NOT NULL |
多重条件(逻辑运算) | AND,OR,NOT |
比较大小
例:查询计算机科学系全体学生的名单。 SELECT Sname FROM Student WHERE Sdept='CS'; 例:查询所有年龄在20岁一下的学生的姓名及年龄。 SELECT Sname,Sage FROM Student WHERE Sage<20; 例:查询考试成绩不及格的学生的学号。 SELECT DISTINCT Sno FROM SC WHERE Grade<60;
确定范围 谓词 BETWEEN ··· AND ···,NOT BETWEEN ··· AND ···可以用来查找属性值在(或不在)指定范围内的元组,其中 BETWEEN 后是范围的下限(即低值),AND 后是范围的上限(即高值)。
例:查询年龄在20~23岁(包括20岁和23岁)之间的学生的姓名、系别和年龄。 SELECT Sname,Sdept,Sage FROM Student WHERE Sage BETWEEN 20 AND 23; 例:查询年龄不在20~23岁之间的学生的姓名、系别和年龄。 SELECT Sname,Sdept,Sage FROM Student WHERE Sage NOT BETWEEN 20 AND 23;
确定集合 谓词 IN 可以用来查找属性值属于指定集合的元组。
例:查询计算机科学系(CS)、数学系(MA)和信息系(IS)学生的姓名和性别。 SELECT Sname,Ssex FROM Student WHERE Sdept IN('CS','MA','IS');
与 IN 相对的谓词是 NOT IN,用于查找属性值不属于指定集合的元组。
例:查询既不是计算机科学系、数学系,也不是信息系的学生的姓名和性别。 SELECT Sname,Ssex FROM Student WHERE Sdept NOT IN('CS','MA','IS');
字符匹配 谓词 LIKE 可以用来进行字符串的匹配。其一般语法格式如下:
[NOT] LIKE '<匹配串>' [ESCAPE '<换码字符>']
其含义是查找指定的属性列值与 <匹配串> 相匹配的元组。<匹配串> 可以是一个完整的字符串,也可以含有通配符%和_。其中:
- %(百分号)代表任意长度(长度可以为0)的字符串。例如 a%b 表示以 a 开头,以 b 结尾的任意长度的字符串。
- _(下横线)代表任意单个字符。
例:查询学号为2024001的学生的详细情况。 SELECT * FROM Student WHERE Sno LIKE '2024001'; 等价于 SELECT * FROM Student WHERE Sno='2024001';
如果 LIKE 后面的匹配串中不含通配符,则可以用=(等于)运算符取代 LIKE 谓词,用!= 或 <>(不等于)运算符取代 NOT LIKE 谓词。
例:查询所有姓刘的学生的姓名、学号和性别。 SELECT Sname,Sno,Ssex FROM Student WHERE Sname LIKE '刘%'; 例:查询姓“欧阳”且全名为三个汉字的学生的姓名。 SELECT Sname FROM Student WHERE Sname LIKE '欧阳_'; /*数据库字符集为ASCII时一个汉字需要两个_;当字符集为GBK时只需要一个_*/ 例:查询名字中第二个字为“阳”的学生的姓名和学号。 SELECT Sname,Sno FROM Student WHERE Sname LIKE '_阳%'; 例:查询所有不姓刘的学生的姓名、学号和性别。 SELECT Sname,Sno,Ssex FROM Student WHERE Sname NOT LIKE '刘%';
如果用户要查询的字符串本身就含有通配符%或_,这时就要使用 ESCAPE ‘<换码字符>’短语对通配字符进行转义。
例:查询DB_Design课程的课程和和学分。 SELECT Cno,Ccredit FROM Course WHERE Cname LIKE 'DB\_Dssign' ESCAPE'\'; 例:查询以“DB_”开头,且倒数第三个字符为i的课程的详细情况。 SELECT * FROM Course WHERE Cname LIKE 'DB\_%i_ _' ESCAPE'\';
涉及空值的查询
例:某些学生选修课程后没有参加考试,所有有选课记录,但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号。 SELECT Sno,Cno FROM SC WHERE Grade IS NULL; /*分数Grade是空值,这里的"IS"不能用(=)代替*/ 例:查所有有成绩的学生学号和课程和。 SELECT Sno,Cno FROM SC WHERE Grade IS NOT NULL;
多重条件查询 逻辑运算符 AND 和 OR 可用来连接多个查询条件。AND 的优先级高于 OR,但用户可以用括号改变优先级。
例:查询计算机科学系年龄在20岁以下的学生姓名。 SELECT Sname FROM Student WHERE Sdept='CS' AND Sage<20; 例:查询计算机科学系(CS)、数学系(MA)和信息系(IS)学生的姓名和性别。 SELECT Sname,Ssex FROM Student WHERE Sdept='CS' OR Sdept='MA' OR Sdept='IS';
ORDER BY 子句
用户可以用 ORDER BY 子句对查询结果按照一个或多个属性列的升序(ASC)或降序(DESC)排列,默认则为升序。
例:查询选修了3号课程的学生的学号及其成绩,查询结果按分数的降序排列。
SELECT Sno,Grade
FROM SC
WHERE Cno='3'
ORDER BY Grade DESC;
对于空值,排序时显示的次序由具体系统实现来决定。例如按升序排,含空值的元组最后显示;按降序排,空值的元组则最先显示。
例:查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列。
SELECT *
FROM Student
ORDER BY Sdept,Sage DESC;
聚集函数
为了增强检索功能,SQL 提供了许多聚集函数。
COUNT(*) | 统计元组个数 |
COUNT([ DISTINCT|ALL ] <列名>) | 统计一列中值的个数 |
SUM([ DISTINCT|ALL ] <列名>) | 计算一列值的总和(此列必须是数值型) |
AVG([ DISTINCT|ALL ] <列名>) | 计算一列值的平均值(此列必须是数值型) |
MAX([ DISTINCT|ALL ] <列名>) | 计算一列值中的最大值 |
MIN([ DISTINCT|ALL ] <列名>) | 计算一列值中的最小值 |
如果指定 DISTINCT 短语,则表示在计算时要取消指定列中的重复值。如果不指定 DISTINCT 短语或指定 ALL 短语(ALL 为默认值),则表示不取消重复值。
例:查询学生总数。
SELECT COUNT(*)
FROM Student;
例:查询选修了课程的学生人数。
SELECT COUNT(DISTINCT Sno)
FROM SC; /*一个学生要选修多门课程,为避免重复计算学生人数,必须在COUNT函数中用DISTINCT短语*/
例:计算选修1号课程的学生平均成绩。
SELECT AVG(Grade)
FROM SC
WHERE Cno='1';
例:查询选修1号课程的学生的最高分数。
SELECT MAX(Grade)
FROM SC
WHERE Cno='1';
例:查询学生2024001选修课程的总学分数。
SELECT SUM(Ccredit)
FROM SC,Course
WHERE Sno='2024001' AND SC.Cno=Course.Cno;
当聚集函数遇到空值时,除 COUNT(*)外,都跳过空值而只处理非空值。
注:WHERE 子句中是不能用聚集函数作为条件表达式的。聚集函数只能用于 SELECT 子句和 GROUP BY 中的 HAVING 子句。
GROUP BY 子句
GROUP BY 子句将查询结果按某一列或多列的值分组,值相等的为一组。
例:求各个课程号及相应的选课人数。
SELECT Cno,COUNT(Sno)
FROM SC
GROUP BY Cno; /*该语句对查询结果按Cno的值分组,所有具有相同Cno值的元组为一组*/
例:查询选修了三门以上课程的学生学号。
SELECT Sno
FROM SC
GROUP BY Sno
HAVING COUNT(*)>3; /*先用GROUP BY子句按Sno进行分组,再用聚集函数COUNT对每一组计数*/
例:查询平均成绩大于等于90分的学生学号和平均成绩。
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno
HAVING AVG(GRADE)>=90; /*WHERE子句不能用聚集函数作为表达式*/
连接查询
若一个查询同时涉及两个以上的表,则称之为连接查询。
连接查询包括等值连接查询、自然连接查询、非等值连接查询、自身连接查询、外连接查询和复合条件连接查询等。
等值与非等值连接查询
连接查询的 WHERE 子句中用来连接两个表的条件称为连接条件或连接谓词,一般格式为:
[<表名1>.]<列名1><比较运算符>[<表名2>.]<列名2>
比较运算符主要有 =,>,<,> =,<=,!=,(或<>)等。
同时,连接谓词还可以使用以下形式:
[<表名1>.]<列名1> BETWEEN [<表名2>.]<列名2> AND [<表名3>.]<列名3>
当连接运算符为=时,称为等值连接。使用其他运算符称为非等值连接。
连接谓词中的列名称为连接字段。连接条件中的各连接字段类型必须是可比的,但名字不必相同。
例:查询每个学生及其选修课程的情况。
SELECT Student.*,SC.* /*学生情况存放在Student表中,学生选课情况存放在SC表中*/
FROM Student,SC
WHERE Student.Sno=SC.Sno /*通过公共属性Sno将Student与SC中同一学生的元组连接起来*/
若再等值连接中把目标列中重复的属性列去掉则为自然连接。
例:查询每个学生及其选修课程的情况。(使用自然连接)
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student,SC
WHERE Student.Sno=SC.Sno
一条 SQL 语句可以同时完成选择和连接查询,这时 WHERE 子句是由连接谓词和选择谓词组成的复合条件。
例:查询选修2号课程且成绩在90分以上的所有学生的学号和姓名。
SELECT Student.Sno,Sname
FROM Student,SC
WHERE Student.Sno=SC.Sno AND /*连接谓词*/
SC.Cno='2' AND SC.Grade>90; /*其他限定条件*/
自身连接
连接操作不仅可以在两个表之间进行,也可以是一个表与其自己进行连接,称为表的自身连接。
例:查询每一门课的间接先行课(即先行课的先行课)
再Course表中只有每门课的直接先行课,没有先行课的先行课,所以需要先找到一门课的先行课,再找到先行课的先行课。
SELECT FIRST.Cno,SECOND.Cpno /*为Course表取两个别名,一个是FIRST,另一个是SECOND*/
FROM Course FIRST,Course SECOND
WHERE FIRST.Cpno=SECOND.Cno;
外连接
在通常的连接操作中,只有满足条件的元组才能作为结果输出,但是有时想把悬浮元组保存在结果关系中,那么就要在其他属性上填空值 NULL,这时就需要使用外连接。
例:查询每个学生及其选修课程的情况。(使用外连接)
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student LEFT OUTER JOIN SC ON(Student.Sno=SC.Sno)
/*也可以使用USING来去掉结果中重复的值:FROM Student LEFT OUTER JOIN SC USING(Sno)*/
注:左外连接列出左边关系中所有的元组,右外连接列出右边关系中的所有元组。
多表连接
例:查询每个学生的学号、姓名、选修的课程及成绩。
SELECT Student.Sno,Sname,Cname,Grade
FROM Student,SC,Course
WHERE Student.Sno=SC.Sno AND SC.Sno=Course.Cno;
关系数据库管理系统在执行多表连接时,通常是先进行两个表的连接操作,再将其连接结果与第三个表进行连接。
嵌套查询
在 SQL 语言中,一个 SELECT-FROM-WHERE 语句成为一个查询块,将一个查询块嵌套在另一个查询块的 WHERE 子句或 HAVING 短语的条件中的查询称为嵌套查询。
在嵌套查询中,上层的查询块称为外层查询或父查询,下层查询块称为内层查询或子查询。SQL 语言允许多层嵌套。
注:子查询的 SELECT 语句中不能使用 ORDER BY 子句,ORDER BY 子句只能对最终查询结果排序。
带有 IN 谓词的子查询
例:查询与“刘晨”在同一个系学习的学生。
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN
(SELECT Sdept
FROM Student
WHERE Sname='刘晨');
在本例中,子查询的查询条件不依赖于父查询,称为不相关子查询。
例:查询选修了课程名为“信息系统”的学生学号和姓名。
SELECT Sno,Sname
FROM Student
WHERE Sno IN /*最后再Student关系中取出Sno和Sname*/
(SELECT Sno
FROM SC
WHERE Cno IN /*然后再SC关系中找出选修了课程的学生学号*/
(SELECT Cno
FROM Course
WHERE Cname='信息系统' /*首先在Course关系中找出“信息系统”的课程号*/
)
);
当然,上例中嵌套查询可以用连接运算代替,而有的是不可以代替的。
带有比较运算符的子查询
带有比较运算符的子查询是指父查询和子查询之间用比较运算符进行连接.
当用户可以确切知道内层查询返回的是单个值时,可以用 =,>,<,> =,<=,!=,或<> 等比较运算符。
例:找出每个学生超过他自己选修课程平均成绩的课程号。
SELECT Sno,Cno
FROM SC x
WHERE Grade>=(SELECT AVG(Grade)
FROM SC y
WHERE y.Sno=x.Sno
)
上例中,子查询中学生的平均成绩要看参数 x.Sno 的值,该值是与父查询相关的,因此这类查询称为相关子查询。
带有 ANY(SOME)或 ALL 谓词的子查询
子查询返回单值时可以用比较运算符,但返回多值时要用 ANY(有的系统用 SOME)或 ALL 谓词修饰符。
使用 ANY 或 ALL 谓词时必须同时使用比较运算符。
> ANY | 大于子查询结果中的某个值 |
> ALL | 大于子查询结果中的所有值 |
< ANY | 小于子查询结果中的某个值 |
< ALL | 小于子查询结果中的所有值 |
>= ANY | 大于等于子查询结果中的某个值 |
>= ALL | 大于等于子查询结果中的所有值 |
<= ANY | 小于等于子查询结果中的某个值 |
<= ALL | 小于等于子查询结果中的所有值 |
= ANY | 等于子查询结果中的某个值 |
= ALL | 等于子查询结果中的所有值(通常无意义) |
!= (或 <>) ANY | 不等于子查询结果中的某个值 |
!= (或 <>) ALL | 不等于子查询结果中的所有值 |
例:查询非计算机科学系中比计算机科学系(CS)任意一个学生年龄小的学生姓名和年龄。
SELECT Sname,Sage
FROM Student
WHERE Sage<ANY(SELECT Sage
FROM Student
WHERE Sdept='CS')
AND Sdept<>'CS'; /*这时父查询块中的条件*/
该查询也可以使用聚集函数来实现:
SELECT Sname,Sage
FROM Student
WHERE Sage <
(SELECT MAX(Sage)
FROM Student
WHERE Sdept='CS')
AND Sdept<>'CS';
例:查询非计算机科学系中比计算机科学系(CS)所有学生年龄都小的学生姓名及年龄。
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';
实际上,使用聚集函数实现子查询通常比直接用 ANY 或 ALL 查询效率要高。
= | <> 或!= | < | <= | > | >= | |
ANY | IN | -- | < MAX | <= MAX | > MIN | >= MIN |
ALL | -- | NOT IN | < MIN | <= MIN | > MAX | >= MAX |
带有 EXISTS 谓词的子查询
EXISTS 代表存在量词
可以利用 EXISTS 来判断
例:查询所有选修了1号课程的学生姓名。
SELECT Sname
FROM Student
WHERE EXISTS /*若内层查询结果非空,则外层的WHERE子句返回真值*/
(SELECT * /*由EXISTS引出的子查询,其目标表达式通常为*,因为该子查询只返回真值或假值*/
FROM SC
WHERE Sno=Student.Sno AND Cno='1');
/*子查询的查询条件依赖于外层父查询的某个属性值(Student的Sno值)*/
与 EXISTS 谓词相对应的是 NOT EXISTS 谓词。
使用 NOT EXISTS 后,若内层查询结果为空,则外层的 WHERE 子句返回真值,否则返回假值。
例:查询没有选修1号课程的学生姓名。
SELECT Sname
FROM Student
WHERE NOT EXISTS
(SELECT *
FROM SC
WHERE Sno=Student.Sno AND Cno='1');
SQL 中没有全称量词(for all),但是可以把带有全称量词的谓词转换为等价的带有存在量词的谓词:
例:查询这样的学生,没有一门课程是他不选修的。
SELECT Sname
FROM Student
WHERE NOT EXISTS
(SELECT *
FROM COURSE
WHERE NOT EXISTS
(SELECT *
FROM SC
WHERE Sno=Student.Sno
AND Cno=Course.Cno));
集合查询
SELECT 语句的查询结果是元组的集合,所以多个 SELECT 语句的结果可进行集合操作。
集合操作主要包括并操作 UNION、交操作 INTERSECT 和差操作 EXCEPT。
注:参加集合操作的个查询结果的列数必须相同;对应项的数据类型也必须相同。
例:查询计算机科学系(CS)的学生及年龄不大于19岁的学生。
SELECT *
FROM Student
WHERE Sdept='CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19;
例:查询选修了课程1或者选修了课程2的学生。
SELECT *
FROM SC
WHERE Cno='1'
UNION
SELECT *
FROM SC
WHERE Cno='2';
例:查询计算机科学系(CS)的学生与年龄不大于19岁的学生的交集。
SELECT *
FROM Student
WHERE Sdept='CS'
INTERSECT
SELECT *
FROM Student
WHERE Sage<=19;
本例也可表示为:
SELECT *
FROM Student
WHERE Sdept='CS' AND
Sage<=19;
例:查询既选修了课程1又选修了课程2的学生。
SELECT *
FROM SC
WHERE Cno='1'
INTERSECT
SELECT *
FROM SC
WHERE Cno='2';
本例也可表示为:
SELECT *
FROM SC
WHERE Cno='1' AND Sno IN
(SELECT Sno
FROM SC
WHERE Cno='2');
例:查询计算机科学系(CS)的学生与年龄不大于19岁的学生的差集。
SELECT *
FROM Student
WHERE Sdept='CS'
EXCEPT
SELECT *
FROM Student
WHERE Sage<=19;
本例也可表示为:
SELECT *
FROM Student
WHERE Sdept='CS' AND Sage>19;
基于派生的查询
子查询不仅可以出现在 WHERE 子句中,还可以出现在 FROM 子句中,这时子查询生成的临时派生表(derived table)成为主查询的查询对象。
例:找出每个学生超过他自己选修课程平均成绩的课程号。
SELECT Sno,Cno
FROM SC,(SELECT Sno,AVG(Grade) FROM SC GROUP BY Sno)
AS Avg_sc(avg_sno,avg_grade) /*生成一个派生表Avg_sc*/
WHERE SC.Sno=Avg_sc.avg_sno and SC.Grade>=Avg_sc.avg_grade;
如果子查询中没有聚集函数,派生表可以不指定属性列,子查询 SELECT 子句后面的列名为其默认名。
例:查询所有选修了1号课程的学生姓名。
SELECT Sname
FROM Student,(SELECT Sno FROM SC WHERE Cno='1')AS SC1
WHERE Student.Sno=SC1.Sno;
需要注意的是,通过 FROM 子句生成派生表时,AS 关键字可以省略,但必须为派生关系指定一个别名。
SELECT 语句的一般格式
SELECT 一般格式为:
SELECT [ALL|DISTINCT]<目标列表达式>[别名][,<目标列表达式>[别名]]···
FROM <表名或视图名>[别名][,<表名或视图名>[别名]]···|(<SELECT语句>)[AS]<别名>
[WHERE<条件表达式>]
[GROUP BY<列名1>[HAVING<条件表达式>]]
[ORDER BY<列名2>[ASC|DESC]];
目标列表达式的可选格式
其中,<属性列名表达式> 可以是由属性列、作用于属性列的聚集函数和常量的任意算术运算(+,-,*,/)组成的运算公式。
聚集函数的一般格式
WHERE 子句的条件表达式的可选格式
数据更新
在数据库中,数据更新操作有三种:向表中添加若干行数据、修改表中的数据和删除表中的若干行数据。
插入数据
SQL 的数据插入语句 INSERT 通常有两种形式,一种是插入一个元组,另一种是插入子查询结果。
插入元组
插入元组的 INSERT 语句的格式为:
INSERT
INTO<表名>[(<属性列1>[,<属性列2>]···)]
VALUES(<常量1>[,<常量2>]···);
若 INTO 子句中没有指明任何属性列名,则新插入的元组必须在每个属性列上均有值。
例:将一个新学生元组(学号:2024001,姓名:咸鱼,性别:男,所在系:IS,年龄:18岁)插入到Student表中。
INSERT
INTO Student(Sno,Sname,Ssex,Sdept,Sage)
VALUES ('2024001','咸鱼','男','IS','18');
例:将学生张成民的信息插入Student表中。
INSERT
INTO Student /*只指出表名,表示新元组要在表的所有属性列上都指定值*/
VALUES ('2024002','张成民','男','IS','18'); /*一定要注意值与属性列一一对应*/
例:插入一条选课记录('2024001','1')
INSERT
INTO SC(Sno,Cno)
VALUES ('2024001','1'); /*系统会在新插入记录的Grade列上个自动赋空值*/
或者
INSERT
INTO SC
VALUES ('2024001','1','NULL'); /*没有明确指出SC属性名,Grade属性列上要明确给出空值*/
插入子查询结果
子查询不仅可以嵌套在 SELECT 语句中用以构造父查询的条件,也可以嵌套在 INSERT 语句中用以生成要插入的批量数据。
INSERT
INTO <表名>[<属性列1>[,<属性列2>]···]
子查询;
例:对每一个系,求学生的平均年龄,并把结果存入数据库。
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;
修改数据
修改操作又称为更新操作,其语句的一般格式为:
UPDATE <表名>
SET <列名>=<表达式>[,<列名>=<表达式>]··· /*表达式的值用于取代相应的属性列值*/
[WHERE<条件>]; /*省略WHERE子句表示要修改所有元组*/
修改一个元组的值
例:将学生2024001的年龄改为22岁。
UPDATE Student
SET Sage=22
WHERE Sno='2024001';
修改多个元组的值
例:将所有学生的年龄增加1岁。
UPDATE Student
SET Sage=Sage+1;
带子查询的修改语句
例:将计算机科学系(CS)全体学生的成绩置零。
UPDATE SC
SET Grade=0
WHERE Sno IN
(SELECT Sno
FROM Student
WHERE Sdept='CS');
删除数据
删除语句的一般格式为:
DELETE
FROM <表名>
[WHERE <条件>]; /*省略WHERE子句表示要删除全部元组*/
删除一个元组的值
例:删除学号为2024001的学生记录。
DELETE
FROM Student
WHERE Sno='2024001';
删除多个元组的值
例:删除所有的学生选课记录。
DELETE
FROM SC;
带子查询的删除语句
子查询同样可以嵌套在 DELETE 语句中,用以构造执行删除操作的条件。
例:删除计算机科学系(CS)所有学生的选课记录
DELETE
FROM SC
WHERE Sno IN
(SELETE Sno
FROM Student
WHERE Sdept="cs");
空值的处理
SQL 语言中允许某些元组的某些属性在一定情况下取空值。
- 该属性应该有一个值,但目前不知道它的具体值。
- 该属性不应该有值。
- 由于某种原因不便于填写。
空值的产生
例:向SC表中插入一个元组,学生号是“2024001”,课程号是“1”,成绩为空。
INSERT INTO SC(Sno,Cno,Grade)
VALUES('2024001','1','NULL');
或
INSERT INTO SC(Sno,Cno)
VALUES('2024001','1');
例:将Student表中学生会为“2024001”的学生所属系改为空值。
UPDATE Student
SET Sdept=NULL
WHERE Sno='2024001';
空值的判断
判断一个属性的值是否为空值,用 IS NULL 或 IS NOT NULL 来表示。
例:从Student表中找出漏填了数据的学生信息。
SELECT *
FROM Student
WHERE Sname IS NULL OR Ssex IS NULL OR Sage IS NULL OR Sdept IS UNLL;
空值的约束条件
属性定义(或者域定义)中有 NOT NULL 约束条件的不能取空值。
加了 UNIQUE 限制的属性不能取空值。
码属性不能取空值。
空值的算术运算、比较运算和逻辑运算
空值与另一个值(包括另一个空值)的算术运算的结果为空值,空值与另一个值(包括另一个空值)的比较运算结果为 UNKNOWN。有了 UNKNOWN 后,传统的逻辑运算中二值(TRUE,FALSE)逻辑就扩展成三值逻辑。
例:找出选修1号课程的不及格的学生。
SELECT Sno
FROM SC
WHERE Grade<60 AND Cno='1';
例:选出选修1号课程的不及格的学生以及缺考的学生。
SELECT Sno
FROM SC
WHERE Grade<60 AND Cno='1'
UNION
SELECT Sno
FROM SC
WHERE Grade IS NULL AND Cno='1';
或
SELECT Sno
FROM SC
WHERE Cno='1' AND (Grade<60 OR Grade IS NULL);
视图
视图是从一个或几个基本表(或视图)导出的表,它与基本表不同,是一个虚表。
数据库只存放视图的定义,而不存放视图对应的数据,这些数据仍存放在原来的基本表中。
定义视图
建立视图
SQL 建立视图的一般格式为:
CREATE VIEW <视图名>[(<列名>[,<列名>]···)] /*CREATE VIEW只是把视图的定义存入数据字典*/
AS<子查询>
[WITH CHECK OPTION];
WHIT CHECK OPTION 表示对视图进行 UPDATE、INSERT 和 DELETE 操作时要保证更新、插入或删除的行满足视图定义中的谓词条件(即子查询中的条件表达式)。
组成视图的属性列名或者全部省略或者全部指定。但以下三种情况必须明确指定视图的所有列名:
- 某个目标列不是单纯的属性名,而是聚集函数或列表达式;
- 多表连接时选出了几个同名列作为视图的字段;
- 需要在视图中为某个列启用新的更合适的名字。
例:建立信息系学生视图。
CREATE VIEW IS_Student
AS
SELECT Sno,Sname,Sage
FROM Student
WHERE Sdept='IS';
WITH CHECK OPTION;
由于有 WITH CHECK OPTION 子句,以后对该视图进行插入、修改和删除操作时,系统会自动加上 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';
例:建立信息系选修了1号课程且成绩在90分以上的学生视图。
CREATE VIEW IS_S2
AS
SELECT Sno,Sname,Grade
FROM IS_S1
WHERE Grade>=90;
带有虚拟列的视图也称为带表达式的视图。
例:定义一个反映学生出生年份的视图。
CREATE VIEW BT_S(Sno,Sname,Sbirth)
AS
SELECT Sno,Sname,2024-Sage /*视图中的出生年份值是通过计算得到的*/
FROM Student;
用带有聚集函数和 GROUP BY 子句的查询来定义视图,这种视图称为分组视图。
例:将学生的学号及平均成绩定义为一个视图。
CREATE VIEW S_G(Sno,Gavg)
AS
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno; /*由于AS子句的SELECT是通过聚集函数得到的,所以必须明确定义S_G视图的各个属性列*/
例:将Student表中所有女生记录定义为一个视图。
CREATE VIEW F_Student(F_sno,name,sex,age,dept)
AS
SELECT *
FROM Student
WHERE Ssex='女';
删除视图
SQL 删除视图的语句格式为:
DROP VIEW <视图名>[CASCADE];
视图删除后视图的定义将从数据字典中删除,如果该视图上还导出了其他视图,则使用 CASCADE 级联删除语句把该视图和它导出的所有视图一起删除。
基本表删除以后,由该基本表导出的所有视图均无法使用,但是视图的定义没有从数据字典中删除。
例:删除视图BT_S和视图IS_S1。
DROP VIEW BT_S; /*成功执行*/
DROP VIEW IS_S1; /*拒绝执行,由于IS_S1视图上导出了IS_S2视图*/
DROP VIEW IS_S1 CASCADE; /*删除了视图IS_S1和由它导出的所有视图*/
查询视图
定义视图后,用户就可以想对基本表一样对视图进行查询了。
例:在信息系学生的视图中找出年龄小于20岁的学生。
SELECT Sno,Sage
FROM IS_Student
WHERE Sage<20;
RDBMS 执行对视图的查询时,首先进行有效性检查,检查查询中涉及的表、视图等是否存在。
如果存在,则从数据字典中取出视图的定义,把定义的子查询和用户的查询结合起来,转换成等价的对基本表的查询,然后再执行修正了的查询。这一转换过程称为视图消解(view resolution)。
上例中转换后的查询语句为:
SELECT Sno,Sage
FROM Student
WHERE Sdept='IS' AND Sage<20;
例:查询选修了1号课程的信息系学生。
SELECT IS_Student.Sno,Sname
FROM IS_Student,SC
WHERE IS_Student.Sno=SC.Sno AND SC.Cno='1';
上例中的查询涉及到了视图 IS_Student(虚表)和基本表 SC,通过这两个表的连接来完成用户的查询请求。
再一般情况下,视图的查询转换是直截了当的,但有些情况下,这种转换不能直接进行。
例:在将学生的学号及平均成绩定义的视图S_G中查询平均成绩在90分以上的学生学号和平均成绩。
SELECT *
FROM S_G
WHERE Gavg>=90;
定义S_G视图的子查询为:
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno;
视图消解后的查询语句为:
SELECT Sno,AVG(Grade)
FROM SC
WHERE AVG(Grade)>=90
GROUP BY Sno;
但是WHERE语句不能用聚集函数作为表达式,因此此修正后的查询会出现语法错误。
正确的转换查询语句应为:
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno
HAVING AVG(Grade)>=90;
目前多少 DBMS 对行列子集视图的查询均能进行正确转换,但对非行列子集视图的查询不一定能做转换。
此类查询应该直接对基本表进行:
SELECT *
FROM (SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno)AS S_G(Sno,Gavg) /*子查询生成一个派生表S_G*/
WHERE Gavg>=90;
注:派生表只是在语句执行时临时定义,语句执行后该定义即被删除。
更新视图
更新视图是指通过视图来 插入(INSERT)、删除(DELETE)和修改(UPDATE)数据。
由于视图是不实际存储数据的虚表,因此对视图的更新最终要转换为对基本表的更新。
例:将信息系学生视图IS_Student中学号为“20204001”的学生姓名改为“咸鱼”。
UPDATE IS_Student
SET Sname='咸鱼'
WHERE Sno='2024001';
转换后的更新语句为:
UPDATE Student
SET Sname='咸鱼'
WHERE Sno='2024001' AND Sdept='IS';
例:向信息系学生视图IS_Student中插入一个新的学生记录,其中学号为“2024002”,姓名为“三木”,年龄为18岁。
INSERT
INTO IS_Student
VALUES('2024002','三木',18);
转换为对基本表的更新:
INSERT
INTO Student(Sno,Sname,Sage,Sdept)
VALUES('2024002','三木',18,'IS');
例:删除信息系学生视图IS_Student中学号为“2024003”的记录。
DELETE
FROM IS_Student
WHERE Sno='2024003';
转换为对基本表的更新:
DELETE
FROM Student
WHERE Sno='2024003' AND Sdept='IS';
在关系数据库中,并不是所有的视图都是可更新的。
例:视图S_G是由学生的学号及平均成绩定义的,其中平均成绩是由Student表中对元组分组计算平均值得来的:
CREATE VIEW S_G(Sno,Gavg)
AS
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno;
如果想将S_G视图中学号为“2024001”学生的平均成绩改为90分,SQL语句如下:
UPDATE S_G
SET Gavg=90
WHERE Sno='2024001'; /*该视图更新是无法转换成对基本表的更新的*/
上例中,视图的更新无法转换成对基本表的更新,因为系统无法修改各科成绩,使得平均分成为 90 分。
一般的,行列子集视图是可以更新的,除此之外,有些视图理论上是可更新的。
目前,各个 RDBMS 一般只允许对行列子集视图进行更新,且各个系统对视图的更新还有更进一步的规定。
视图的作用
视图可以简化用户操作:
- 视图机制可以使用户将注意力集中在所关系的数据上。
视图使用户能以多种角度看待同一数据。
视图对重构数据库提供了一定程度的逻辑独立性:
- 数据的物理独立性:用户的应用程序不依赖于数据库的物理结构。
- 数据的逻辑独立性:数据库重构造时,如增加新的关系等,用户的应用程序不会受到影响。
视图能够对机密数据提供安全保护。
适当利用视图可以更清晰的表达查询。