第3章 关系数据库标准语言SQL
3.1 SQL概述⚓
3.1.2 SQL的特点⚓
结构化查询语言(Structured Query Language,SQL)是关系数据库的标准语言。
目前,没有一个数据库系统能够支持 SQL 标准的所有概念和特性。
SQL 集数据查询、数据操纵、数据定义和数据控制功能于一体,主要特点包括:
-
综合统一
非关系模型(层次模型、网状模型)的数据语言一般都分为:
- 模式数据定义语言, DDL
- 外模式数据定义语言, 外模式 DDL
- 数据存储有关的描述语言,DSDL
- 数据操作语言,DML
它们分别用于定义模式、外模式、内模式和进行数据的存取与处置。但是SQL 可以独立完成数据库生命周期的全部活动。
-
高度非过程化
非关系数据模型的数据操纵语言是“面向过程”的语言,用“过程化”语言完成某项请求必须指定存取路径。
而 SQL进行数据操作时,只要提出“做什么”,而无须指明“怎么做”,因此无须了解存取路径。存取路径的选择以及 SQL 的操作过程由系统自动完成。
-
面向集合的操作方式
-
以同一种语法结构提供多种使用方式
既是独立的语言又是嵌入式语言(可以嵌入到高级语言程序中,比如 Java)。
-
语言简洁,易学易用
3.1.3 SQL 的基本概念⚓
支持 SQL 的关系数据库管理系统同样支持关系数据库三级模式结构。如图3.1所示,其中外模式包括若干视图(view)和部分基本表(base table),数据库模式包括若干基本表,内模式包括若干存储文件(stored file)。
存储文件的逻辑结构组成了关系数据库的内模式。
视图是一个虚表。
3.3 数据定义⚓
SQL 的数据定义功能包括 模式定义、表定义、视图和索引的定义(或定义数据库、定义基本表、定义视图和定义索引)。
一个关系数据库管理系统的实例中可以建立多个数据库,一个数据库中可以建立多个模式,一个模式下通常包括多个表、视图和索引等数据库对象。
3.3.1 模式的定义与删除⚓
定义:
CREATE SCHEMA <模式名> AUTHORIZATION <用户名>;
删除:
DROP SCHEMA <模式名> <CASCADE | RESTRICT>;
- CASCADE,级联: 自动删除包含在该模式中的对象(表、函数等),然后删除所有 依赖于那些对象的对象。
- RESTRICT,限制: 如果该模式含有任何对象,则拒绝删除它。
3.3.2 基本表的定义、删除与修改⚓
如果完整性约束涉及该表的多个属性列,则必须定义在表级上。
修改:
删除:
DROP TABLE <表名> [RESTRICT | CASCADE];
3.3.3 索引的建立与删除⚓
数据库索引有多种类型,常见索引包括:
- 顺序文件上的索引 是针对按指定属性值升序或降序存储的关系,在该属性上建立一个顺序索引文件,索引文件由属性值和相应的元组指针组成。
- B+树索引 是将索引属性组织成 B+树形式,B+树的叶结点为属性值和相应的元组指针。B+树索引具有动态平衡的优点。
- 散列索引 是建立若干个桶,将索引属性按照其散列函数值映射到相应桶中,桶中存放索引属性值和相应的元组指针。散列索引具有查找速度快的特点。
- 位图索引 是用位向量记录索引属性中可能出现的值,每个位向量对应一个可能值。
索引虽然能够加速数据库查询,但需要占用一定的存储空间,当基本表更新时,索引要进行相应的维护,这些都会增加数据库的负担,因此要根据实际应用的需要有选择地创建索引。
用户不必也不能显式地选择索引。索引属于内模式的范畴。
建立索引:
在SQL 语言中,建立索引使用 CREATE INDEX 语句,其一般格式为
CREATE [UNIQUE] [CLUSTER] INDEX <索引名> ON <表名>(<列名> [<次序>] [ ,<列名> [<次序>]]···)
UNIQUE 表明此索引的每一个索引值只对应唯一的数据记录。
CLUSTER 表示要建立的索引是聚簇索引。有关聚簇索引的概念在第7章7.5.2小节关系模式存取方法选择中介绍。
修改索引:
ALTER INDEX <旧索引名> RENAME TO <新索引名>;
删除索引:
DROP INDEX <索引名>;
3.3.4 数据字典⚓
数据字典(DD)是关系数据库系统内部的一组系统表,它记录了数据库中所有的定义信息,包括关系模式定义、视图定义、索引定义、完整性约束定义、各类用户对数据库的操作权限、统计信息等。
3.4 数据查询⚓
一般格式为:
SELECT [ALL | DISTINCT] <目标列表达式> [,<目标列表达式>] ···
FROM <表名或视图名>[,表名或视图名···]| (<SELECT 语句>)[AS]<别名>
[WHERE <条件表达式>]
[GROUP BY <列名1>[HAVING<条件表达式>]]
[ORDER BY <列名2> [ASC|DESC]];
3.4.1 单表查询⚓
<目标列表达式> 不仅可以是表中的属性列,也可以是表达、字符串常量、函数等。
聚集函数只能用于 select 子句和 group by 中的 having 子句。
分组后的聚集函数将作用于每一个分组,即每一组都有应该函数值。having 短语给出了选择分组的条件,满足条件的分组才会被选出来。
where 子句中不能使用聚集函数作为条件表达式。
3.4.2 连接查询⚓
若一个查询同时涉及两个以上的表,称之为连接查询。包括 等值连接查询、自然连接查询、非等值连接查询、自身连接查询、外连接查询和复合条件连接查询等。
- 等值与非等值连接查询
连接查询的 where 子句中用来连接两个表的条件称为连接条件或连接谓词,一般格式为
[<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2>
此外还可以使用下面形式:
[<表名1>.]<列名1> between [<表名2>.]<列名2> and [<表名2>.]<列名3>
当连接运算符为=
时称为等值连接
,其他的称为非等值连接
。
连接谓词中的列名称为连接字段
。连接条件中的各连接字段类型必须是可比的。
- 外连接
3.4.3 嵌套查询⚓
一个SELECT-FROM-WHERE
语句称为一个查询块。将一个查询块嵌套在另一个查询块的 where
子句或 having
短语的条件中的查询称为嵌套查询。
上层的查询块称为外层查询或父查询,下层查询块称为内层查询或子查询。
SQL 语言允许多层嵌套。但是子查询的 select 语句不能使用 order by 子句,该子句只能对最终查询结果排序。有些嵌套可以用连接运算符替代。
子查询条件不依赖于父查询,称为不相关子查询。否则称为相关子查询,整个查询语句称为相关嵌套查询。
嵌套查询的分类:
- 带有 IN 谓词的子查询
-
带有比较运算符的子查询。父查询和子查询之间用比较运算符进行连接。当用户能确切知道内层查询返回的是单个值时,可以用比较运算符连接。
-
带有 ANY(SOME)或 ALL 谓词的子查询。返回多值时要用 ANY(SOME)或 ALL 谓词修饰符修饰比较运算符。
-
带有 EXISTS / NOT EXISTS 谓词的子查询。带有 EXISTS 谓词的子查询不返回任何数据,只返回逻辑真值
true
或false
。由 EXISTS 引出的子查询,其目标列表达式通常都用*
,因为带 EXISTS的子查询只返回真值或假值,给出列名无实际意义。
3.4.4 集合查询⚓
多个 select 语句的结果可进行集合操作,主要包括 并操作 UNION
、交操作 INTERSECT
和差操作 EXCEPT
。
使用 UNION
时系统会自动去掉重复元组,若要保留则使用 UNION ALL
。
3.4.5 基于派生表的查询⚓
子查询还可以出现在FROM
子句中,此时子查询生成的临时表叫做派生表。必须为派生表指定一个别名。
3.4.6 SELECT语句的一般格式⚓
其中,MAX 中的列名可以是字符、字符串、日期和数值类型等,不限制数据类型。
SELECT 语句执行的结果是一个临时表,也叫做派生表。
3.5 数据更新⚓
3.5.1 插入数据⚓
子查询结果也可插入:
INSERT INTO <表名> [(<属性列 1> [,<属性列 2>]...)] 子查询;
3.5.2 修改数据⚓
子查询也可嵌套在 update 语句的 where 子句中。
3.5.3 删除数据⚓
子查询也可嵌套在 delete 语句的 where 子句中。
3.6 空值的处理⚓
外连接会产生空值,空值的关系运算也会产生空值。
用IS NULL
或IS NOT NULL
来判断空值。
属性定义(或域定义)中有NOT NULL
约束条件的结果为空值,空值与另一个值(包括空值)的算术运算结果是空值,空值与另一个值(包括空值)的比较运算结果为UNKNOWN
。
- T: TRUE
- F: FALSE
- U: UNKNOWN
3.7 视图⚓
视图是从一个或几个基本表(或视图)导出的表。与基本表不同,是一个虚表。数据库中只存放视图的定义,不存放视图对应的数据。
3.7.1 定义视图⚓
CREATE VIEW <视图名> [(<列名> [,<列名>]...)]
AS <子查询>
[WITH CHECK OPTION];
其中,子查询可以是任意的 select 语句。
WITH CHECK OPTION
表示对视图进行 update、insert、delete 操作时要保证更新、插入或删除的行满足视图定义中的谓词条件(即子查询中的条件表达式),关系数据库管理系统会自动加上谓词条件。
组成视图的属性列名要么全部省略要么全部指定。但下列三种情况下必须指定组成视图的所有列名:
- 某个目标列不是单纯的属性名,而是聚集函数或列表达式
- 多表连接时选择了几个同名列作为视图的字段
- 需要在视图中为某个列启用新的更合适的名字
若一个视图是从单个基本表导出的,并且只是去掉了基本表的某些行和某些列,但保留了主码,则称这类视图为行列子集视图。
由基本数据经过各种计算派生出的数据一般是不存储的。定义视图时可以根据应用的需要设置一些派生属性列。这些派生属性由于在基本表中并不实际存在,也称它们为虚拟列。带虚拟列的视图也称为带表达式的视图。
用带有聚集函数和 group by 子句的查询来定义视图,称为分组视图。
删除视图:
DROP VIEW <视图名> [CASCADE];
CASCADE 级联删除语句可以使视图删除后将导出的其它视图也一起删除。
但是基本表删除后,需要显式地使用 DROP VIEW 删除。
3.7.2 查询视图⚓
关系数据库管理系统执行对视图的查询时,首先进行有效性检查,检查查询中涉及的表、视图等是否存在。如果存在,则从数据字典中取出视图的定义,把定义中的子查询和用户的查询结合起来,转换成等价的对基本表的查询,然后再执行修正了的查询。这一转换过程称为视图消解(view resolution)。
但定义视图并查询视图与基于派生表(临时表)的查询是有区别的。视图一旦定义,其定义将永久保存在数据字典中,之后的所有查询都可以直接引用该视图。而派生表只是在语句执行时临时定义,语句执行后该定义即被删除。
3.7.3 更新视图⚓
对视图的更新最终要转换为对基本表的更新。
但并不是所有的视图都是可更新的。因为不一定能唯一地有意义地转换成对相应基本表的更新。目前,各个关系数据库管理系统一般都只允许对行列子集视图进行更新,而且各个系统
由于各系统实现方法上的差异,这些规定也不尽相同。 例如,DB2 规定:
- 若视图是由两个以上基本表导出的,则此视图不允许更新。
- 若视图的字段来自字段表达式或常数,则不允许对此视图执行 INSERT 和 UPDATE 操作,但允许执行 DELETE 操作。
- 若视图的字段来自聚集函数,则此视图不允许更新。
- 若视图定义中含有 GROUP BY 子句,则此视图不允许更新。
- 若视图定义中含有 DISTINCT 短语,则此视图不允许更新。
- 若视图定义中有嵌套查询,并且内层查询的FROM 子句中涉及的表也是导出该视图的基本表,则此视图不允许更新。
- 一个不允许更新的视图上定义的视图也不允许更新。
3.7.4 视图的作用⚓
- 能够简化用户的操作
- 使用户能以多种角度看待同一数据
- 视图对重构数据库提供了一定程度的逻辑独立性
- 能够对机密数据提供安全保护
- 适当利用视图可以更清晰地表达查询