第五章 数据库完整性 5.1 实体的完整性 5.2 参照完整性 5.3 用户定义的完整性 5.4 完整性约束命名子句 第五章 数据库完整性 5.1 实体的完整性 5.2 参照完整性 5.3 用户定义的完整性 5.4 完整性约束命名子句 *5.5 约中的完整性限制 5.6 触发器 5.7 小结
一、什么是数据库的完整性 数据的正确性和相容性 防止不合语义的数据进入数据库。 例: 学生的年龄必须是整数,取值范围为14--29; 例: 学生的年龄必须是整数,取值范围为14--29; 学生的性别只能是男或女; 学生的学号一定是唯一的; 学生所在的系必须是学校开设的系; 完整性:真实地反映现实世界
二、DBMS的完整性控制机制 1. 定义功能 一个完善的完整性控制机制应该允许用户定义各类完整性约束条件。 2. 检查功能 检查用户发出的操作请求是否违背了完整性约束条件 立即执行的约束(Immediate constraints) 语句执行完后立即检查是否违背完整性约束 延迟执行的约束(Deferred constrainsts) 完整性检查延迟到整个事务执行结束后进行 例:银行数据库中“借贷总金额应平衡”的约束就应该是延迟执行的约束 3. 违约反应 如果发现用户的操作请求使数据违背了完整性约束条件,则采取一定的动作来保证数据的完整性。 拒绝该操作 其他处理方法
5.1 实体完整性 一、实体完整性定义 实体完整性规则:关系中的码不能为空也不能重复。 5.1 实体完整性 一、实体完整性定义 实体完整性规则:关系中的码不能为空也不能重复。 定义方法:在CREATE TABLE中用PRIMARY KEY。 二、实体完整性检查和违约处理 检查:插入操作或更改码的值时。 处理:拒绝执行
5.2 参照完整性 一、参照完整性定义 参照完整性规则:关系中的外码或者取空值,或者等于被参照关系中某个元组的主码值。 5.2 参照完整性 一、参照完整性定义 参照完整性规则:关系中的外码或者取空值,或者等于被参照关系中某个元组的主码值。 定义方法:在CREATE TABLE中用FOREIGN KEY。 二、参照完整性检查和违约处理 检查:对参照表和被参照表进行增、删、改操作时,有可能破坏参照完整性,必须进行检查。 处理:见表5.1 表5.1 可能破坏参照完整性的情况及违约处理 被参照表 参照表 违约处理 可能被破坏完整性参照 插入元组 拒绝 修改主码值 删除元组 拒绝/级连删除/设置为空
1. 在被参照关系中删除元组时的问题 例:要删除Student关系中Sno=200215122的元组, 而SC关系中有4个元组的Sno都等于200215122 。 级联删除:将SC关系中所有4个Sno= 200215122的元组一起删除。如果参照关系同时又是另一个关系的被参照关系,则这种删除操作会继续级联下去 受限删除:系统将拒绝执行此删除操作。 置空值删除:将SC关系中所有Sno= 200215122的元组的Sno值置为空值。 在学生选课数据库中,显然第一种方法和第二种方法都是对的。第三种方法不符合应用环境语义。
2. 在参照关系中插入元组时的问题 出现违约操作的情形 需要在参照关系中插入元组,而被参照关系不存在相应的元组。 违约反应 受限插入 递归插入 仅当被参照关系中存在相应的元组,其主码值与参照关系插入元组的外码值相同时,系统才执行插入操作,否则拒绝此操作。 首先向被参照关系中插入相应的元组,其主码值等于参照关系插入元组的外码值,然后向参照关系插入元组。 例:向SC关系插入( 200215125 ,1,90)元组,而Student关系中尚没有Sno= 200215125的学生 受限插入: 系统将拒绝向SC关系插入( 200215125 ,1,90)元组。 递归插入: 系统将首先向Student关系插入Sno= 200215125的元组,然后向SC关系插入( 200215125 ,1,90)元组。
3. 修改被参照关系中主码的问题 两种策略 (1) 允许修改主码 (2) 不允许修改主码
(1)允许修改主码策略 违约操作 要修改被参照关系中某些元组的主码值,而参照关系中有些元组的外码值正好等于被参照关系要修改的主码值。 要修改参照关系中某些元组的主码值,而被参照关系中没有任何元组的外码值等于被参照关系修改后的主码值。 违约反应 (1):修改的关系是被参照关系:与删除类似 级连修改 受限修改 置空值修改 修改被参照关系中主码值同时,用相同的方法修改参照关系中相应的外码值。 拒绝此修改操作。只当参照关系中没有任何元组的外码值等于被参照关系中某个元组的主码值时,这个元组的主码值才能被修改。 修改被参照关系中主码值,同时将参照关系中相应的外码值置为空值。 违约反应 (2) : 修改的关系是参照关系:与插入类似。 受限插入 递归插入
(1)允许修改主码策略 例:将Student关系中Sno= 200215123的元组中Sno值改为200215128。而SC关系中有 4个元组的Sno= 200215123 级联修改:将SC关系中4个Sno= 200215123元组中的Sno值也改为200215128 。如果参照关系同时又是另一个关系的被参照关系,则这种修改操作会继续级联下去。 受限修改:只有SC中没有任何元组的Sno= 200215123时,才能修改 Student表中Sno= 200215123的元组的Sno值改为200215128 。 置空值修改:将Student表中Sno= 200215123的元组的Sno值改为 200215128 。而将SC表中所有Sno= 200215123的元组的Sno值置为空 值。 在学生选课数据库中只有第一种方法是正确的。
参照完整性的实现 RDBMS在实现参照完整性时: 需要向用户提供定义主码、外码的机制; 向用户提供按照自己的应用要求选择处理依赖关系中对应的元组的方法; 一般地,当对参照表和被参照表的操作违反了参照完整性,系统选用默认策略,即拒绝执行。如果想让系统采用其它的策略则必须在创建表的时候显式说明。 [例4] 显式说明参照完整性的违约处理。 CREATE TABLE SC (Sno CHAR(9) NOT NULL, Cno CHAR(4) NOT NULL, Grade SMALLINT, PRIMARY key (Sno, Cno), FOREIGN KEY (Sno) REFERENCES Student(Sno) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (Cno) REFERENCES Course(Cno) ON DELETE ON ACTION ON UPDATE CASCADE, );
5.3 用户定义的完整性 一、属性上约束条件的定义 5.3 用户定义的完整性 一、属性上约束条件的定义 在CREATE TABLE中定义属性的同时可以根据应用要求,定义属性上的约束条件,即属性值的限制。 列值非空(NOT NULL) 列值唯一(UNIQUE) 检查列值是否满足一个布尔表达式(CHECK) [例5] 在定义SC表时,说明Sno,Cno,Grade属性不允许取空值。 CREATE TABLE SC (Sno CHAR(9) NOT NULL, Cno CHAR(4) NOT NULL, Grade SMALLINT NOT NULL, PRIMARY key (Sno, Cno), FOREIGN KEY (Sno) REFERENCES Student(Sno), FOREIGN KEY (Cno) REFERENCES Course(Cno) );
[例6] 建立部门表DEPT,要求部门名称Dname列取值唯一,部门编号Deptno列为主码。 CREATE TABLE DEPT (Deptno NUMERIC(2) NOT NULL, Dname CHAR(9) UNIQUE, Location char(10), PRIMARY key (Deptno) ); [例7] Student表的Ssex 只允许取“男”或“女”。 CREATE TABLE Student (Sno CHAR(9) PRIMARY KEY, Sname CHAR(8) NOT NULL, Ssex CHAR(2) CHECK(Seex IN(‘男’,‘女’)), Sage SMALLINT, Sdept CHAR(20) );
[例8] SC表中的值应该在0和100之间。 CREATE TABLE SC (Sno CHAR(9) NOT NULL, Cno CHAR(4) NOT NULL, Grade SMALLINT CHECK(Grade>=0 AND Grade<=100), PRIMARY key (Sno, Cno), FOREIGN KEY (Sno) REFERENCES Student(Sno), FOREIGN KEY (Cno) REFERENCES Course(Cno) ); CREATE TABLE SC (Sno CHAR(9) NOT NULL,; Cno CHAR(4) NOT NULL, ; Grade int(3) CHECK(GRADE>=0 AND GRADE<=100),; PRIMARY key Sno+Cno tag kk,; FOREIGN KEY Sno tag k1 REFERENCES Student ,; FOREIGN KEY Cno tag k2 REFERENCES Course)
二、属性上的约束条件检查和违约处理——拒绝 三、元组上的约束条件定义 [例9] 当学生性别是男时不允许以Ms.打头。 CREATE TABLE Student (Sno CHAR(9) PRIMARY KEY, Sname CHAR(8) NOT NULL, Ssex CHAR(2) CHECK(Seex IN(‘男’,‘女’)), Sage SMALLINT, Sdept CHAR(20) CHECK (Seex=‘女’ OR Sname NOT LIKE ‘MS.%’ ); 四、元组上的约束条件检查和违约处理——拒绝
5.4 完整性约束命名子句 一、完整性约束命名子句 5.4 完整性约束命名子句 一、完整性约束命名子句 CONSTRAINT<完整性约束条件名> [PRIMARY KEY 短语|FOREIGN KEY短语|CHECK短语] [例10]建立学生登记表Student,要求学号在90000至99999之间,姓名不能为空,年龄<30,性别只能是‘男’或‘女’ 。 CREATE TABLE Student (Sno CHAR(6) CONSTRAINT C1 CHECK(Sno BETWEEN 90000 AND 99999), Sname CHAR(8) CONSTRAINT C2 NOT NULL, Sage NUMERIC(3) CONSTRAINT C3 CHECK(Sage<30) , Ssex CHAR(2) CONSTRAINT C4 CHECK(Seex IN(‘男’,‘女’)), CONSTRAINT StudentKey PRIMARY KEY(Sno) );
[例11] :建立教师表TEACHER,要求每个职工的应发工资不低于3000元。 应发工资实际上就是实发工资列Sal与扣除项Deduct之和。 CREATE TABLE TEACHER (Eno NUMBER(4) PRIMARY KEY, Ename CHAR(10), Job CHAR(8), Sal NUMBER(7,2), Deduct NUMBER(7,2) Deptno NUMBER(2), CONSTRAINTS TEACHERKEY FOREIGN KEY (Deptno) REFERENCES DEPT(Deptno) CONSTRAINTS C1 CHECK (Sal + Deduct >=3000));
二、修改表中的完整性限制 [例12] 去掉[例10]中对性别的限制。 ALTER TABLE Student DROP CONSTRAINT C4; [例13] 修改表中的约束条件,要求学号改为在900000~999999之间年龄小于30改为小于40。 ALTER TABLE Student DROP CONSTRAINT C1; ALTER TABLE Student ADD CONSTRAINT C1 CHECK(Sno BETWEEN 90000 0AND 999999) ; DROP CONSTRAINT C3; ALTER TABLE Student ADD CONSTRAINT C3 CHECK(Sage <40) ;
二、修改表中的完整性限制 [例14]建立一个性别域,并声明性别取值的范围。 CREATE DOMAIN GenderDomain CHAR(2) CHECK(VALUE IN (‘男’,‘女’)); 这样[例10]中的说明可以改为:Seex GenderDomain
5.6 触发器 数据库触发器:是用户定义在关系表上的一类由事务驱动的特殊过程; 5.6 触发器 数据库触发器:是用户定义在关系表上的一类由事务驱动的特殊过程; 一旦定义,任何用户对该数据的增、删、改操作均由服务器自动激活相应的触发器,在核心层进行集中的完整性控制; 触发器类似于约束,但比约束更加灵活,可以实施比更为复杂的检查和操作,具有 更精细更强大的数据控制能力。 定义其它的完整性约束时,需要用数据库触发器(Trigger)来实现。
5.6 触发器 一、定义触发器 说明: VFP的定义触发器语句: 5.6 触发器 一、定义触发器 CREATE TRIGGER <触发器名>{BEFORE|AFTER} <触发事件> ON <表名> FOR FACH {BOW|STATEMENT} [WHEN <触发条件>] <触发动作体> 说明: 表的拥有者即创建表的用户才可以在表上创建触发器,并且一个表上只能创建一定数量的触发器; 触发器名可以包含模式名,也可以不包含模式名。同一模式下,触发器名必须是唯一 的,并且触发器名和<表名>必须在同一模式下; 表名是指当这个表数据发生变化时,将激活定义在该表上相应<触发事件> 的触发器; 触发事件可以是INSERT、DELETE和UPDATE,也可以是这几个事件的组合。UPDATE 后面还可以有OF<触发列,……>,即进一步指明修改哪些列时触发器激活。 触发类型:FOR EACH ROW(行级触发器)和FOR EACH STATEMENT(语句级触发器) VFP的定义触发器语句: CREATE TRIGGER ON TableName FOR DELETE | INSERT | UPDATE AS lExpression
5.6 触发器 [例18] 为教师表Teacher定义完整性规则 “教授的工资不得低于4000元,如果低于4000元,自动改为4000元” 5.6 触发器 [例18] 为教师表Teacher定义完整性规则 “教授的工资不得低于4000元,如果低于4000元,自动改为4000元” CREATE TRIGGER INSERT_OR_UPDATE_SAL BEFORE INSERT OR UPDATE ON Teacher FOR EACH ROW AS BEGIN IF (:new.Pos=‘教授’) AND (:new.sal<4000) THEN :new.Sal:=4000; END IF; END;
5.6 触发器 [例19] 当教师表Teacher中的工资发生变化后就自动在工资变化表SAL_LOG中增加一条相应的记录。
5.6 触发器 二、激活触发器 三、删除触发器 执行该表上的BEFORE触发器(多个时,按字母顺序); 激活触发器上的SQL语句; 5.6 触发器 二、激活触发器 触发器的执行是由事件激活的,并数据库服务器自动执行的。同一个表上定义的多个触发器激活时遵循如下的执行顺序: 执行该表上的BEFORE触发器(多个时,按字母顺序); 激活触发器上的SQL语句; 执行该表上的AFTER触发器(多个时,按字母顺序) 。 三、删除触发器 DROP TRIGGER <触发器名> ON <表名>