数据库的完整性指的是数据的正确性和相容性
正确性指的是数据是符合显示世界语义、反映当前实际状况的
相容性指的是数据库同一对象再不同关系表的数据是符合逻辑的
为了维护数据库的完整性,数据库系统必须能够实现如下功能
1.提供定义完整性约束条件的机制
2.提供完整性检查的方法
3.进行违约处理
关系型数据库的三种完整性
1.实体完整性(主码)
实体完整性在create table 中用primary key 定义,有两种说明方法,一种是列级约束条件,一种是表级约束条件,对于多个属性构成的码,只能用表记约束条件
create table a
(name char(20) primary key, //primary key 是在列级中被定义的
age int(200) not null
);
或者
create table a
( name char(20),
age int(200) not null,
primary key(name) //primary key 是在表级中被定义的
);
将属性组定义为主码
create table a
(name char(20) not null,
age int(200) not null,
primary key(name,age) //只能用表级
);
实体完整性检查和违约处理
使用primary key定义主码之后,每当用户对主码列进行操作时,数据库管理系统就会自行检查,包括
1.检查主码值是否唯一,如果不唯一则拒绝插入或修改
2.检查主码的各个属性是否为空,只要有一个为空就拒绝插入或修改
从而保证实体完整性
关系行数据库会在主码上自动创建索引,通过索引查找基本表是否存在新的主码值,从而提高效率。
2.参照完整性(外码)
实体完整性在create table 中用foreign key 定义哪些列为外码,用peferences指名这些外码参照哪些表的主码
例如关系sc中(sno,cno)是主码,sno、cno分别参照了student表的主码和course表的主码
create sc
(sno char(9) not null,
cno char(9) not null,
grade smallint.
primary key(sno,cno),
foreign key (sno) peferences student(sno),
foreign key (cno) peferences course(cno)
);
参照完整性的检查和违约处理
因为参照完整性把两个表中相对应的元组连接起来了,所以对被参照表和参照表的增删改操作可能会破环参照完整性,对此系统提供了三种策略加以处理
1.拒绝(not action)执行
不允许该操作执行。该策略一般为默认策略
2.连级(cascade)操作
当删除或修改被参照表的一个元组导致参照表(sc)不一致时,删除或修改参照表的所有不一致的元组
3.设为空值 (set null)
例如关系sc中(sno,cno)是主码,sno、cno分别参照了student表的主码和course表的主码
create sc
(sno char(9) not null,
cno char(9) not null,
grade smallint.
primary key(sno,cno),
foreign key (sno) peferences student(sno)
on delete cascade //当删除student表中的元组时,连级删除sc表的元组
on update cascade,
foreign key (cno) peferences course(cno)
on delete on action //当删除course表中的元组造成与sc表不一致时,拒绝删除
on update cascade
);
3.用户定义的完整性
属性上的约束条件
在create table 中定义属性的同时,可以根据应用要求定义属性上的约束条件,包括:
1.列值非空(not null)
2.列值唯一(unique)
3.检查列值是否满足一个条件表达式(check语句)
create table a
(name char(9) not null unique primary key
sex char(2) check(sex in('男','女'))
);
属性上的约束条件的检查和违约处理
当往表里插入元组或修改属性的值时,关系数据库管理系统将检查属性上的约束条件,检查是否满足,不满足将拒绝执行
元组上的约束条件
可以用check语句定义元组上的约束条件
当学生性别是男时,名字不能用MS打头
create table student
(
sno char(9),
sname char(8) not null,
sex char(2),
primary key (sno),
check(sex='女' or sname not like 'MS%') //定义元组中sname和sex两个属性之间 的约束
);
元组上的约束条件检查和违约处理
不满足拒绝执行
完整性约束命名子句
constraint <完整性约束条件名><完整性约束条件>
条件包括 not null.,unique,primary key,foreign key,check等
create table a
(
sno char(8) ,
sname char(8) constraint c1 not null,
constrant c2 primary key(sno)
);
可以使用alter table 语句修改表的完整性限制
alter table a
drop constrant c1;
断言
可以使用create assertion 语句,通过声明性断言来指定更具一般性的约束,可以定义涉及多个表或聚集操作的比较比较复杂的完整性约束。
创建断言后,任何对断言中所涉及关系的操作都会触发关系数据库管理系统对断言的检查,任何使断言不为真的操作都会被拒绝
创建断言的语句格式:
create assertion <断言名><check 子句>
每个断言都会有一个名字,check子句的约束条件和where子句的表达式类似
例 :限制数据库课程最多60名学生选修
create assertion asse
check (60>=(select count(*)) /断言的谓语涉及聚集操作count的sql语句
from course,sc
where sc.cno=course.cno and course.cname='数据库'
);
每当学生选修课程时,将在sc表中插入一条元组,断言触发检查,如果选修数据库课程的认识超过60,check子句返回值为‘假’,对sc表的插入操作将被拒绝。
删除断言:
drop assertion <断言名>;
触发器
触发器又叫事件-条件-动作规则。
当特定的事件(增删改,事务的结束等)发生时,对规则的条件进行检查,如果条件成立则执行规则中的动作(类似if语句),否则不执行该动作。规则中的动作体可以很复杂,可以设计其他表和其他数据库对象,通常是一段sql存储过程。
触发器的一般格式为
create tigger <触发器名> //每当触发事件发生时,该触发器将被激活
{ before | after }<触发器事件> on <表名> //指名触发器激活的时间是在触发事件之前还 是之后可以用update、delete等,也可以用 update of <触发列,.....>进一步表明修改哪些列时触发
referncing new | old row as <变量> //referncing指出引用的变量 ,new指插入表,old 指删除表
for each {row |statement} //定义触发器的类型,指明动作体执行的频率,row是行级触发 器,statement是语句级,若一个表的行数为100,对表的一 个属性列的值进行修改,row要执行100次,statement只执 行一次
[ when <触发条件>] <触发动作体> //仅当触发条件为真时才执行触发动作体动作体可以 为一个匿名的PL/SQL过程块,也可以是对己创建存储过程的调用 如果是row级别的,用户可在过程体中使用new和old,如果是 statement级别的不可以用new和old。可以不要触发条件
如果触发动作体执行失败,激活触发器的事件(对数据库的增删改操作)就会终止执行,触发器的目标表或可能影响的对象不发生变化。
例子:当对表sc的grade属性进行修改时若分数增加10%,则将此次操作记录到另一个表sc_U(sno、cno、oldgrade、newgrade)其中oldgrade是旧的成绩,newgrade是新的成绩。
create tigger sc_T
after update of grade on sc //在sc表的grade列被更新后触发
referncing
oldrow as oldtuple,
newrow as newtuple
//旧表名为oldtuple,新表名为newtuple
for each row
when (newtuple.grade >=1.1 * oldtuple.grade)
insert
into sc_u(sno,cno,oldgrade,newgrade)
values(oldtuple.sno,oldtuple.cno,oldtuple.grade、newtuple.grade)
将每次对表student的插入操作所增加的学生个数记录到表student-insertLog表中
create tigger insertStudent
after insert on student
referncing
new table as delta
for each statement //执行完全部insert操作再执行触发器动作
insert into student-InsertLog(Number)
select count(*)
from delta
//dalta是一个关系名,其模式与student相同,包含的元组是insert语句增加的元组
定义一个before行级触发器,为教师表teacher定义完整性规则"教授工资不得低于4000,如果低于4000自动改为4000"
create tigger tea
before insert or update on teacher
referncing
new row as newtuple
for each row
begin //这是个PL/SQL过程块
If(newtuple.job='教授')and (newtuple.sal<4000) //因为是行级的所以可以引用
then newtuple.sal =4000; //使用插入或更新后的新值
end if //循环结束
end; //动作体结束
激活触发器
对于多个触发器的激活顺序为
1.before触发器
2.激活触发器的sql语句
3.after触发器
多个before或after触发器,遵循先创建先执行的原则
删除触发器
drop tigger <触发器名> on <表名>