国际惯例:本章主要的内容一览:
概述
数据库的完整性是指数据的正确性和相容性。正确性是指数据符合现实世界语义,符合当前的情况,相容性是指数据库同一对象在不同关系表中的数据是符合逻辑的。
实体完整性
定义实体完整性
关系模型的实体完整性是在创建表的时候用主码PRIMARY KEY来定义。实体完整性其实就是主码不为空且唯一。
例:
create table student(
sno varchar(9) primary key, //列级别主码
sname varchar(30),
sage smallint
//这样定义:primary key(sno),就是表级主码
);
完整性检查和违约处理
检查与处理:
- 主码是否唯一,不唯一拒绝插入或删除。
- 主码的各个属性是否为空,若为空拒绝删除或修改。、
参照完整性
参照完整性是在foreign key定义哪些列为外码,用references指定这些外码参照哪些表的主码。
create table sc(
sno char(9) not null,
cno char(9) not null,
grade smallint,
primary key(sno,cno), //表级定义实体完整性
foreign key(sno) references student(sno),
foreign key(cno) references course(cno) //表级定义参照完整性
);
参照完整性要保证相关联表的相容性。若一个数据库对象A中的字段在另一个表B中出现,那么表B中的这个字段:
1、不为空,在对象A中存在。
2、为空(该字段不为主码)。
例:student表中记录有sno为”1001”,”1002”的学生记录,在sc表中你不能插入sno为“1003”的学生记录,或者你不能在sc中修改学生记录的sno为不存在与student中的值。
当不一致操作发生时,有如下方法处理:
- 拒绝操作执行(数据库一般的默认操作)
- 级联(CASCADE)操作:当删除或修改被参照表(若上面的student表是sc的被参照表)导致数据不一致时,会删除或修改参照表中的所有不一致的元组(也叫记录)。
- 设置空值
用户定义完整性
用户定义的完整性可分为在属性上的和元组上的。
属性上的约束条件
- 列非空:not null
- 列值唯一:unique
- 列值检查:check 短语
例:
create table studen(
sno char(9) not null,
sname char(30) unique,
sage smallint check(sage >= 0 and sage <= 60)
);
元组上的约束条件
create table studen(
sno char(9) not null,
sname char(30) unique,
sage smallint,
check(sage >= 0 and sage <= 60)
);
完整性约束命名子句
定义
constraint <完整性约束命名条件名> <完整性约束条件>
例:
create table student(
sno char(9),
constraint student_key primary key(sno)
域中的完整性限制
域是一组表示具有相同数据类型值的集合。使用域可以使得完整性约束条件改变时只需要改变域中的定义而不需要一个个更改要修改的各个属性上的约束。
例:建立一个用来表示性别的域
create domain gender_domain char(2)
check(value in('男','女'));
对属性sex约束: sex gender_domain
断言
断言用来表示更具有一般性的约束,可以用来实现比较复杂的约束。任何使断言不为真值的操作都会被拒绝执行。
创建断言
create assertion <断言名> <check子句>
例:限制一门课最多60人选修
create assertion course_max
check(60 >= select count(*) from sc group by cno);
删除断言
drop assertion <断言名>
断言复杂的情况下,系统检测和维护断言开销较高,使用时要小心!。
注:Mysql不支持断言。
触发器
触发器是用户定义在表关系上的一类右事件驱动的特殊过程。触发器类似于约束,但是比约束更加灵活
。
定义触发器
触发器又叫”事件-条件-动作”规则。
create trigger <触发器名>
{before | after} <触发事件> on <表名>
referencing new|old row as <变量>
for each {row | statement}
[when <触发条件>] <触发动作>
触发器不能定义在视图上,只能定义在表上。
before、after是触发时机,表示触发动作之前或之后。
for each row是行触发器,for each statement是语句级触发器。行触发器在sql语句发生时执行记录条数次触发动作,语句级触发器执行一次。
例:定义一个before触发器,让教师表teacher的工资不低于4000元,若低于4000,修改工资为4000。
create trigger insert_or_update_sal
before insert or update on teacher
referencing new row as newTuple
for each row //行级触发器
begin
if(newTuple.sal < 4000)
then newTuple.sal = 4000;
end if
end;
可以看到触发器起到了约束表内容的作用,确保了数据库的完整性。
激活触发器
触发器由触发事件激活,由数据库服务器自动执行。
触发器执行顺序:
- 先before触发器
- 激活触发器上的SQL语句
- 执行after触发器
对于同一表上的同一before触发器,则是“谁先创建谁先执行”。
删除触发器
drop trigger <触发器名> on <表名>
触发器功能强大,但是因为在每次访问一个表时,都可能触发一个触发器,这样会影响系统的性能,所以需要谨慎使用。