数据库复习">数据库复习
CH5 完整性
5.1 完整性约束
数据库完整性是指数据库中数据在逻辑上的一致性、正确性、有效性和相容性,那么完整性约束就是指用户插入、修改和删除操作时,DBMS为了保证数据库逻辑上的一致性、正确性、有效性和相容性所必需要检查的约束条件
C.J.Date在《An Introduction to Database Systems》一书中描述了四种完整性约束:
类型约束 属性约束 关系变量约束 数据库约束
C.J.Date提出的理论多半是建立在他自创的Tutorial D这个概念型数据库操作语言上的,下面的描述也是基于Tutorial D,注意不要和SQL混淆
(1)类型约束
类型约束是关于自定义类型的种类(或就是数域)以及值大小的约束,例如我们自定类型weight是实数类型且要求weight必须大于0,那么用Tutorial D定义一个类型约束如下:
TYPE weight POSSREP(RATIONAL) CONSTRAINT the_weight(weight) > 0.0;
POSSREP是possible representation(可能的表达方式),RATIONAL是有理数,the_加weight(前面提到过这是C.J.Date提出的对类型的操作符号,表示取值)weight作用于weight表示取值
(2)属性约束
属性约束就是定义关系时定义属性的类型产生的隐式约束,Tutorial D定义一个关系如下:
VAR S BASE RELATION(S# S#, status integer, city char);
比如上例的status就需要隐式遵守类型integer的类型约束
(3)关系变量约束
关系变量约束是对关系中元组的约束,如限定在伦敦的供应商状态一定是20:
Constraint sc1 is_empty(S where city = 'London' and status ~= 20);
关系变量约束总是立即检查的
(4)数据库约束
关系变量约束是针对单个关系变量内部属性的约束(可以把关系变量就理解为关系/表),若约束涉及多个关系变量,则称之为数据库约束
如下的数据库约束,限定零件商的个数必须等于供应表中零件商的个数:
Constraint dbc1 count(SP(p#)) = count(P(p#));
(5)约束设计的黄金准则(Golden Rule)
关于Golden Rule,C.J.Date在这里想要表达的是我们定义的所有完整性约束都称之为内部约束,用户和DBMS都很清楚,比如体重必须大于0
然而我们设计的系统还有很多其他的外部约束,比如说我的体重是69.5,那么可以插入一个元组(jcguo, 69.5),但是插入(jcguo, 100.5)说我是个大胖子DBMS也是允许的,但这违反了现实世界的约束
这届涉及到之前在完整性定义中包括的正确性,C.J.Date认为这部分的完整性应该由用户或者说DBA在数据库外部限定,而不是交给DBMS
5.2 键Key
数据库中可以定义一种特殊的完整性约束——键(key,或者有时也翻译为码,我叫键比较顺口)
(1)各种键的定义
我们先来弄清楚各种键的定义:
super key:超键,在关系中能够唯一标识元组的属性集 candidate key:候选键(一般叫候选码),不含有多余属性/不可规约的超键 primary key:主键,用户选做唯一表识元组的候选键,主键不能为null alternate key:可选键,候选键中除了主键以外,没有被用户选中的候选键 foreign key:外键,是依赖于其他关系用于保证数据库逻辑完整性的约束
前四个key都很好理解,下面着重理解一下外键
(2)外键
关系R1声明在属性a1上创建外键FK,那么有:
这个外键FK必须reference(引用or以来)于另一个关系R2的候选键CK(一般reference另一个关系的主键,设CK创建于属性a2上) 这个reference的作用就是保证R1中属性a1中出现的值全部都在R2的a2中出现(完整性约束)
注意,外键FK并不要求R2中属性a2(CK)中出现的值都必须在R1中属性a1中出现,只是说单方面的约束:一旦在FK中出现则必须在CK中出现
外键还有另一个最重要的特性:referential action(关联动作),关联动作是一个隐式的特殊的触发器(每当满足出发条件时都会出发的动作集合)
下面在讲SQL完整性时会详细阐述SQL所支持的关联动作
5.3 SQL完整性
再次强调之前我们复习的所有完整性都是抽象性的概念,需要理解,那么这一小节SQL完整性则需要记忆了
(1)域约束
域约束(Domain Constraints)是SQL中对属性取值范围的约束,SQL声明域约束是在create table时完成的,支持带名称的显式约束声明以及不带名称的便捷约束声明两种方式:
create table Student( S# char(10), name char(20), gender char(1), constraint gc check (gender in ('F', 'M')) );
和下面等价:
create table Student( S# char(10), name char(20), gender char(1) check (gender in ('F', 'M')) );
check从句中可以使用常用的比较关系操作符号,也可以使用in构造复合语句
给约束命名是为了某些特殊情况我们需要对约束进行修改,见我另外一篇博文:
另外SQL支持对已声明的table添加约束,使用alter table语句,本课程暂不要求
(2)主键
SQL主键声明也是在create table时声明的,声明主键也有两种方式(显式和便捷式,显式主键不需要名字,因为一个关系/表只能有一个主键):
create table Student( S# char(10), name char(20), gender char(1) check (gender in ('F', 'M')), primary key (S#) );
等价于:
create table Student( S# char(10) primary key, name char(20), gender char(1) check (gender in ('F', 'M')) );
需要注意的是主键不能为空,不能插入一条不包含主键/主键为null的元组
primary key也可以作用于多个属性,如同前面概念讲解中所提到的,如何设计依需求而定
(3)unique
SQL中实现候选码使用unique约束,一个关系可以有多条unique约束
这句话翻译自老师ppt,个人觉得需要补充:
SQL中淡化了candidate key的概念 unique约束不仅可以实现候选码,也可以实现超码,也就是它没有不可约的限制
声明uniqle约束和主键类似,举例略
(4)外键
Foreign key之前留了个坑,这里直接举例吧:
create table Dept( D# char(3) primary key, name char(20), type char(20) check (type in ('engineering', 'science', 'business')) );
先创建了一个table Dept是系的关系,它的主键是D#