基本概念
数据库的完整性(integrity)是指数据的正确性(correctness)和相容性(compat-ability):
- 数据的正确性是指数据是符合现实世界语义、反映当前实际状况的
- 数据的相容性是指数据库同一对象在不同关系表中的数据是符合逻辑的。
数据库的完整性是为了防止数据库中存在不符合语义的数据,也就是防止数据库中存在不正确的数据。因此,完整性检查和控制的防范对象是不合语义的、不正确的数据,防止它们进入数据库。
而数据库的安全性是保护数据库防止恶意破坏和非法存取。因此,安全性控制的防范对象是非法用户和非法操作,防止他们对数据库数据的非法存取。
为维护完整性 DBMS
必须要实现如下功能:
- 提供定义完整性约束条件的机制
- 完整性约束条件:是数据库中数据必须满足的语义条件规则
- SQL 标准使用了一系列概念来描述完整性,包括关系模型的实体完整性、参照完整性和用户定义完整性
-
提供完整性检查的方法:检查数据是否满足完整性约束条件的机制。一般在
INSERT
、UPDATE
、DELETE
语句执行后开始检查,也可以在事务提交时检查。检查这些操作执行后数据库中的数据是否违背了完整性约束条件。 -
进行违约处理:数据库管理系统若发现用户的操作违背了完整性约束条件将采取一定的动作,如拒绝实体完整性(NOACTION)执行该操作或级联(CASCADE)执行其他操作,进行违约处理以保证数据的完整性。
实体完整性
关系模型的实体完整性在 CREATE TABLE
中用 PRIMARY KEY
定义。
-
对单属性构成的码有两种说明方法
- 定义为列级约束条件,即直接在列定义中使用
PRIMARY KEY
关键字。
- 定义为列级约束条件,即直接在列定义中使用
CREATE TABLE table_name(
Sno CHAR(10) PRIMARY KEY,
-- ...
)
- 定义为表级约束条件,即在列定义之后,使用
PRIMARY KEY
关键字并括上需要作为主键的列名。
CREATE TABLE table_name(
Sno CHAR(10),
-- ...
PRIMARY KEY(Sno)
)
- 对多个属性构成的码只有一种说明方法,即定义为表级约束条件。
CREATE TABLE table_name(
Sno CHAR(10),
Cno CHAR (10),
-- ...
PRIMARY KEY(Sno,Cno)
)
实体完整性检查和违约处理
用 PRIMARY KEY
短语定义了关系的主码后,每当用户程序对基本表插入一条记录或对主码列进行更新操作时,关系数据库管理系统将按照关系数据库的实体完整性规则自动进行检查:
-
检查主码值是否唯一,如果不唯一则拒绝插入或修改。
-
检查主码的各个属性是否为空,只要有一个为空就拒绝插入或修改。
检查记录中主码值是否唯一的一种方法是进行全表扫描,依次判断表中每一条记录的主码值与将插入记录的主码值(或者修改的新主码值)是否相同。
全表扫描是十分耗时的。为了避免对基本表进行全表扫描,关系数据库管理系统一般都在主码上自动建立一个索引,如B+树索引,通过索引查找基本表中是否已经存在新的主码值将大大提高效率。
参照完整性
关系模型的参照完整性在 CREATE TABLE
中用 FOREIGN KEY
短语定义哪些列为外码,用 REFERENCES
短语指明这些外码参照哪些表的主码。
CREATE TABLE SC(
Sno CHAR(9)NOT NULL,
Cno CHAR(10) NOT NULL,
-- ...
-- 表级定义实体完整性
PRIMARY KEY(Sno,Cno),
-- 表级定义参照完整性
FOREIGN KEY(Sno) REFERENCES Student(Sno),
FOREIGN KEY(Cno) REFERENCES Course(Cno)
)
参照完整性检查
参照完整性将两个表中的相应元组联系起来了。因此,对被参照表和参照表进行增删、改操作时有可能破坏参照完整性,必须进行检查以保证这两个表的相容性。
可能破坏参照完整性的情况:
-
SC
表中增加一个元组,该元组的Sno
属性值在表Student
中找不到一个Sno
属性值与之相等的元组。 -
修改
SC
表中的一个元组,修改后该元组的Sno
属性值在表Student
中找不到一个元组,其Sno
属性值与之相等。 -
从
Student
表中删除一个元组,造成SC
表中某些元组的Sno
属性值在表Student
中找不到一个元组,其Sno
属性值与之相等。 -
修改
Student
表中一个元组的Sno
属性,造成SC
表中某些元组的Sno
属性值在表Student
中找不到一个元组,其Sno
属性值与之相等
违约处理
当上述的不一致发生时,系统可以采用以下策略加以处理:
-
拒绝
NOACTION
执行:不允许该操作执行。该策略一般设置为默认策略。 -
级联
CASCADE
操作:当删除或修改被参照表的一个元组导致与参照表的不一致时,删除或修改参照表中的所有导致不一致的元组。 -
设置为空值
NULL
:当删除或修改被参照表的一个元组时造成了不一致,则将参照表中的所有造成不一致的元组的对应属性设置为空值。(设置为主码的外码不能设置为空值,违反实体完整性)
当对参照表和被参照表的操作违反了参照完整性时,系统选用默认策略,即拒绝执行。
如果想让系统采用其他策略则必须在创建参照表时显式地加以说明:
CREATE TABLE SC
(
Sno CHAR(9)
Sno CHAR(4)
PRIMARY KEY(Sno,Cno),
FOREIGN KEY(Sno) REFERENCES Student(Sno)
-- 删除 Student 表的元组时,级联删除本表相应元组
ON DELETE CASCADE
-- 更新 Student 表中的 Sno 时,级联更新本表相应元组
ON UPDATE CASCADE,
FOREIGN KEY(Cno) REFERENCES Course(Cno)
-- 删除 Course 表的元组造成不一致时,拒绝执行
ON DELETE NO ACTION
-- 更新 Course 表中的 Cno 时,级联更新本表相应元组
ON UPDATE CASCADE
);
用户自定义的完整性
用户自定义完整性针对某一具体应用所涉及的数据必须满足的语义要求,目前的关系数据库管理系统都提供了定义和检验这类完整性的机制,使用了和实体完整性、参照完整性相同的技术和方法来处理它们,而不必由应用程序承担这一功能。
-
属性上的条件约束:在
CREATE TABLE
中定义属性的同时,可以根据应用要求定义属性上的约束条件,即属性值限制,包括:-
NOTNULL
:列值非空 -
UNIQUE
:列值唯一 -
CHECK(condition)
短语:检查列值是否满足一个条件表达式
-
CREATE TABLE table_name(
Sno CHAR(10) NOT NULL PRIMARY KEY;
Cno CHAR(10) UNIQUE NOT NULL,
Grade INT CHECK(Grade>=0 AND Grade<=100)
-- ...
)
- 属性上约束条件的检查和违约处理:当往表中插入元组或修改属性的值时,关系数据库管理系统将检查属性上的约束条件是否被满足,如果不满足则操作被拒绝执行。
- 元组上的约束条件:与属性上约束条件的定义类似,在
CREATE TABLE
中可以用CHECK短语
定义元组上的约束条件,即元组级的限制。同属性值限制相比,元组级的限制可以设置不同属性之间的取值的相互约束条件。
CREATE TABLE table_name(
Gender CHAR(4),
Sname VARCHAR(10),
-- ...
CHECK(Gender='男' OR Sname NOT LIKE 'Ms.%')
)
- 当向表中插入元组或修改属性的值时,关系数据库管理系统将检查元组上的约束条件是否被满足,如果不满足则操作被拒绝执行。
完整性约束条件子句
SQL 还在 CREATE TABLE 语句中提供了完整性约束命名子句CONSTRAINT
,用来对完整性约束条件命名从而可以灵活地增加、删除一个完整性约束条件。
-
列级约束:直接在列定义中使用
PRIMARY KEY
关键字。 -
表级约束:在列定义之后,使用
PRIMARY KEY
关键字并括上需要作为主键的列名。
创建 CONSTRAINT 子句
CONSTRAINT 'constraint_name' constraint_condition
-
constraint_name
:完整性约束条件名 -
constraint_condition
:完整性约束条件(UNIQUE
、CHECK
等)-
UNIQUE
约束:保证列或列组合的值是唯一的,但允许NULL值的存在。 -
CHECK
约束:定义列值必须满足的条件,可以是算术或逻辑表达式。
-
CREATE TABLE table_name(
Sno CHAR(10)
CONSTRAINT con1 NOT NULL, PRIMARY KEY,
Sage INT
CONSTRAINT con2 CHECK(Sage<=18 AND Sage>=0)
)
修改表中的完整性约束条件
借助 ALTER TABLE
语句可以动态地添加或删除表中的完整性限制
删除限制:
ALTER TABLE table_name
DROP CONSTRAINT con1
添加限制:
ALTER TABLE table_name
ADD CONSTRAINT con3 UNIQUE(Sage)
若需要修改限制,则可以删除指定限制后重新添加限制。
注意事项
-
在使用复合主键(由多个列组成)时,确保所有组合的值在所有行中都是唯一的。
-
当使用
CHECK
约束时,确保条件逻辑的正确性,避免无效或过于复杂的约束条件。 -
在修改约束之前,考虑其对现有数据的影响,确保不会违反新约束。
断言 ASSERTION
在 SQL 中可以使用数据定义语言中的 CREATE ASSERTION
语句,通过声明性断言(declarative assertions)来指定更具一般性的约束(如涉及多表、聚集操作等)。可以定义涉及多个表或聚集操作的比较复杂的完整性约束。
断言创建以后,任何对断言中所涉及关系的操作都会触发关系数据库管理系统对断言的检查,任何使断言为 FALSE 的操作都会被拒绝执行。
MySQL 不支持 ASSERTION 关键字
创建断言
在SQL中,使用 CREATE ASSERTION
语句来创建断言
CREATE ASSERTION <断言名><CHECK 子句>
每个断言都被赋予一个名字,<CHECK 子句>
中的约束条件与 WHERE 子句的条件表达式类似。
删除断言
DROP ASSERTION<断言名>
如果断言很复杂,则系统在检测和维护断言上的开销较高,这是在使用断言时应该注意的。