Skip to content

第3章 关系数据库标准语言SQL

3.1 SQL概述

3.1.2 SQL的特点

结构化查询语言(Structured Query Language,SQL)是关系数据库的标准语言。

目前,没有一个数据库系统能够支持 SQL 标准的所有概念和特性。

SQL 集数据查询、数据操纵、数据定义和数据控制功能于一体,主要特点包括:

  1. 综合统一

    非关系模型(层次模型、网状模型)的数据语言一般都分为:

    • 模式数据定义语言, DDL
    • 外模式数据定义语言, 外模式 DDL
    • 数据存储有关的描述语言,DSDL
    • 数据操作语言,DML

    它们分别用于定义模式、外模式、内模式和进行数据的存取与处置。但是SQL 可以独立完成数据库生命周期的全部活动。

  2. 高度非过程化

    非关系数据模型的数据操纵语言是“面向过程”的语言,用“过程化”语言完成某项请求必须指定存取路径。

    而 SQL进行数据操作时,只要提出“做什么”,而无须指明“怎么做”,因此无须了解存取路径。存取路径的选择以及 SQL 的操作过程由系统自动完成。

  3. 面向集合的操作方式

  4. 以同一种语法结构提供多种使用方式

    既是独立的语言又是嵌入式语言(可以嵌入到高级语言程序中,比如 Java)。

  5. 语言简洁,易学易用

3.1.3 SQL 的基本概念

支持 SQL 的关系数据库管理系统同样支持关系数据库三级模式结构。如图3.1所示,其中外模式包括若干视图(view)和部分基本表(base table),数据库模式包括若干基本表,内模式包括若干存储文件(stored file)。

存储文件的逻辑结构组成了关系数据库的内模式。

视图是一个虚表。

3.3 数据定义

SQL 的数据定义功能包括 模式定义、表定义、视图和索引的定义(或定义数据库、定义基本表、定义视图和定义索引)。

一个关系数据库管理系统的实例中可以建立多个数据库,一个数据库中可以建立多个模式,一个模式下通常包括多个表、视图和索引等数据库对象。

3.3.1 模式的定义与删除

pgsql 中的数据模式

定义:

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 连接查询

若一个查询同时涉及两个以上的表,称之为连接查询。包括 等值连接查询、自然连接查询、非等值连接查询、自身连接查询、外连接查询和复合条件连接查询等。

  1. 等值与非等值连接查询

连接查询的 where 子句中用来连接两个表的条件称为连接条件连接谓词,一般格式为

[<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2>

此外还可以使用下面形式:

[<表名1>.]<列名1> between [<表名2>.]<列名2> and [<表名2>.]<列名3>

当连接运算符为=时称为等值连接,其他的称为非等值连接

连接谓词中的列名称为连接字段。连接条件中的各连接字段类型必须是可比的。

  1. 外连接

左外连接

3.4.3 嵌套查询

一个SELECT-FROM-WHERE语句称为一个查询块。将一个查询块嵌套在另一个查询块的 where 子句或 having 短语的条件中的查询称为嵌套查询

上层的查询块称为外层查询父查询,下层查询块称为内层查询子查询

SQL 语言允许多层嵌套。但是子查询的 select 语句不能使用 order by 子句,该子句只能对最终查询结果排序。有些嵌套可以用连接运算符替代。

子查询条件不依赖于父查询,称为不相关子查询。否则称为相关子查询,整个查询语句称为相关嵌套查询

嵌套查询的分类:

  • 带有 IN 谓词的子查询
  • 带有比较运算符的子查询。父查询和子查询之间用比较运算符进行连接。当用户能确切知道内层查询返回的是单个值时,可以用比较运算符连接。

    例3-57 相关子查询

  • 带有 ANY(SOME)或 ALL 谓词的子查询。返回多值时要用 ANY(SOME)或 ALL 谓词修饰符修饰比较运算符。

    ANY 修饰符

  • 带有 EXISTS / NOT EXISTS 谓词的子查询。带有 EXISTS 谓词的子查询不返回任何数据,只返回逻辑真值truefalse。由 EXISTS 引出的子查询,其目标列表达式通常都用*,因为带 EXISTS的子查询只返回真值或假值,给出列名无实际意义。

    例 3-60

    例 3-62

3.4.4 集合查询

多个 select 语句的结果可进行集合操作,主要包括 并操作 UNION、交操作 INTERSECT 和差操作 EXCEPT

使用 UNION 时系统会自动去掉重复元组,若要保留则使用 UNION ALL

3.4.5 基于派生表的查询

子查询还可以出现在FROM子句中,此时子查询生成的临时表叫做派生表。必须为派生表指定一个别名。

3.4.6 SELECT语句的一般格式

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 NULLIS 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 操作时要保证更新、插入或删除的行满足视图定义中的谓词条件(即子查询中的条件表达式),关系数据库管理系统会自动加上谓词条件。

组成视图的属性列名要么全部省略要么全部指定。但下列三种情况下必须指定组成视图的所有列名:

  1. 某个目标列不是单纯的属性名,而是聚集函数或列表达式
  2. 多表连接时选择了几个同名列作为视图的字段
  3. 需要在视图中为某个列启用新的更合适的名字

若一个视图是从单个基本表导出的,并且只是去掉了基本表的某些行和某些列,但保留了主码,则称这类视图为行列子集视图

由基本数据经过各种计算派生出的数据一般是不存储的。定义视图时可以根据应用的需要设置一些派生属性列。这些派生属性由于在基本表中并不实际存在,也称它们为虚拟列。带虚拟列的视图也称为带表达式的视图。

用带有聚集函数和 group by 子句的查询来定义视图,称为分组视图

删除视图:

DROP VIEW <视图名> [CASCADE];

CASCADE 级联删除语句可以使视图删除后将导出的其它视图也一起删除。

但是基本表删除后,需要显式地使用 DROP VIEW 删除。

3.7.2 查询视图

关系数据库管理系统执行对视图的查询时,首先进行有效性检查,检查查询中涉及的表、视图等是否存在。如果存在,则从数据字典中取出视图的定义,把定义中的子查询和用户的查询结合起来,转换成等价的对基本表的查询,然后再执行修正了的查询。这一转换过程称为视图消解(view resolution)。

但定义视图并查询视图与基于派生表(临时表)的查询是有区别的。视图一旦定义,其定义将永久保存在数据字典中,之后的所有查询都可以直接引用该视图。而派生表只是在语句执行时临时定义,语句执行后该定义即被删除。

3.7.3 更新视图

对视图的更新最终要转换为对基本表的更新。

但并不是所有的视图都是可更新的。因为不一定能唯一地有意义地转换成对相应基本表的更新。目前,各个关系数据库管理系统一般都只允许对行列子集视图进行更新,而且各个系统

由于各系统实现方法上的差异,这些规定也不尽相同。 例如,DB2 规定:

  1. 若视图是由两个以上基本表导出的,则此视图不允许更新。
  2. 若视图的字段来自字段表达式或常数,则不允许对此视图执行 INSERT 和 UPDATE 操作,但允许执行 DELETE 操作。
  3. 若视图的字段来自聚集函数,则此视图不允许更新。
  4. 若视图定义中含有 GROUP BY 子句,则此视图不允许更新。
  5. 若视图定义中含有 DISTINCT 短语,则此视图不允许更新。
  6. 若视图定义中有嵌套查询,并且内层查询的FROM 子句中涉及的表也是导出该视图的基本表,则此视图不允许更新。
  7. 一个不允许更新的视图上定义的视图也不允许更新。

3.7.4 视图的作用

  1. 能够简化用户的操作
  2. 使用户能以多种角度看待同一数据
  3. 视图对重构数据库提供了一定程度的逻辑独立性
  4. 能够对机密数据提供安全保护
  5. 适当利用视图可以更清晰地表达查询