数据库完整性
这个是指数据的正确性和数据的相容性。
为了数据库的完整性,数据库管理系统必须提供以下策略
提供定义定义完整性约束条件的机制
提供完整性检查方法
违约处理
本章主要内容
(1) 在列级定义主码
CREATE TABLE girlfriend
(stuname char(10) primary key,
girlfriendName char(10) NOT NULL,
girlfriendAge char(10),
girlfriendPhone int);
(2)在表级定义主码
CREATE TABLE girlfriend
(stuname char(10),
girlfriendName char(10) NOT NULL,
girlfriendAge char(10),
girlfriendPhone int
primary key(stuname));
**插入或对主码列进行更新操作时,**RDBMS按照实体完整性规则自动进行检查。包括:
检查主码值是否唯一,如果不唯一则拒绝插入或修改
检查主码的各个属性是否为空,只要有一个为空就拒绝插入或修改
检查主码是否唯一的一种办法是全表扫描,为了避免全表扫描,RDBMS核心一般在主码上自动建立索引
(1) 在表级定义参照完整性
将女朋友表中的学生名与学生表中的学生名相关连
CREATE TABLE girlfriend
(stuname nvarchar(50) primary key,
girlfriendName char(10) NOT NULL,
girlfriendAge char(10),
girlfriendPhone int,
foreign key(stuname) references [dbo].[Student](Sname) -- 在表级定义参照完整性
);
一个参照完整性是将两个表中相应的元组联系起来,对参照表和被参照表进行增删改查操作时有可能破坏参照完整性,必须进行检查
被参照表(Student) | 参照表(girfriend) | 违约处理 |
---|---|---|
可能破坏参照完整性 | 插入元组 | 拒绝 |
可能破坏参照完整性 | 修改外码值 | 拒绝 |
删除元组 | 可能破坏参照完整性 | 拒绝/级连删除/设置为空值 |
修改主码值 | 可能破坏参照完整性 | 拒绝/级连修改/设置为空值 |
参照完整性的违约处理
(1) 拒绝(no action)执行
(2)级联(CASCADE)操作
(3)设置为空值(SET-NULL)
对于参照完整性,除了定义外码,还定义外码是否为空
显示处理参照完整性违约处理示例
(2)显示参照完整性的违约示例
CREATE TABLE girlfriend2
(stuname nvarchar(50) primary key,
girlfriendName char(10) NOT NULL,
girlfriendAge char(10),
girlfriendPhone int,
foreign key(stuname) references [dbo].[Student](Sname) -- 在表级定义参照完整性
ON DELETE CASCADE /*级联删除SC表中相应的元组*/
ON UPDATE CASCADE /*级联更新SC表中相应的元组*/
--ON DELETE NO ACTION
/*当删除course 表中的元组造成了与SC表不一致时拒绝删除*/
--ON UPDATE NO ACTION
/*当更新course表中的cno时,级联更新SC表中相应的元组*/
);
create table 时定义属性上的约束条件
(1)列值空值
CREATE TABLE girlfriend
(stuname nvarchar(50),
girlfriendName char(10) NOT NULL,--列值非空
girlfriendAge char(10),
girlfriendPhone int
);
(2)列值唯一
CREATE TABLE girlfriend
(stuname nvarchar(50) UNIQUE,--列值唯一
girlfriendName char(10),
girlfriendAge char(10),
girlfriendPhone int UNIQUE,--列值唯一);
(3)check约束,对性别,年龄等约束;
CREATE TABLE girlfriend4
(stuname nvarchar(50),
girlfriendName char(10),
girlfriendSEX char(2) check(girlfriendSEX IN ('男','女')),--性别约束
girlfriendAge int check(girlfriendAge between 18 and 20) ---年龄约束
foreign key(stuname) references [dbo].[Student](Sname) -- 在表级定义参照完整性
);
属性上约束条件检查和违约处理
插入元组或修改属性的值时,关系数据库管理系统检查属性上的约束条件是否被满足
如果不满足则操作被拒绝执行
在CREATE TABLE时可以用CHECK短语定义元组上的约束条件,即元组级的限制
同属性值限制相比,元组级的限制可以设置不同属性之间的取值的相互约束条件
CREATE TABLE girlfriend0
(stuname nvarchar(50),
girlfriendName char(10),
girlfriendSex char(2),
girlfriendAge int check(girlfriendAge between 18 and 20),
girlfriendPhone int,
CHECK (girlfriendSex='女' OR girlfriendName NOT LIKE 'Ms.%')
/*定义了元组中Sname和 Ssex两个属性值之间的约束条件*/
);
性别是女性的元组都能通过该项检查,因为Ssex=‘女’成立;
当性别是男性时,要通过检查则名字一定不能以Ms.打头
元组上约束条件检查和违约处理
插入元组或修改属性的值时,关系数据库管理系统检查属性上的约束条件是否被满足
如果不满足则操作被拒绝执行
(1)完整性约束命名子句
constraint <完整性约束条件名> <完整性约束条件>
CREATE TABLE girlfriend10
(stuname nvarchar(50) CONSTRAINT C1 NOT NULL,
girlfriendName char(10),
girlfriendSex char(2) CONSTRAINT C2 CHECK (girlfriendSex IN ( '男','女')),
girlfriendAge int CONSTRAINT C3 check(girlfriendAge between 18 and 20), girlfriendPhone int,
);
(2)删除约束
ALTER TABLE girlfriend10 DROP CONSTRAINT C1;
(3)修改约束
ALTER TABLE Student ADD CONSTRAINT C3 check(girlfriendAge between 8 and 30);
(1)定义断言
CREATE ASSERTION <断言名>
[例5.18] 限制数据库课程最多60名学生选修
CREATE ASSERTION ASSE_SC_DB_NUM
CHECK (60 >= (select count(*)
/*此断言的谓词涉及聚集操作count的SQL语句*/
From Course,SC
Where SC.Cno=Course.Cno and Course.Cname ='数据库')
);
(2)删除断言
DROP ASSERTION <断言名>;
如果断言很复杂,则系统在检测和维护断言上的开销较高,这是在使用断言时应该注意的。
触发器(Trigger)是用户定义在关系表上一类事件驱动的特殊过程
CREATE TRIGGER语法格式
CREATE TRIGGER <触发器名>
{BEFORE | AFTER} <触发事件> ON <表名>
REFERENCING NEW|OLD ROW AS<变量>
FOR EACH {ROW | STATEMENT}
[WHEN <触发条件>]<触发动作体>
定义触发器语法说明
(1)拥有表的用户才可以定义触发器
(2) 触发器名
(3)表名
(4)触发事件
触发事件可以是INSERT、DELETE或UPDATE
也可以是这几个事件的组合
还可以UPDATE OF<触发列,…>,即进一步指明修改哪些列时激活触发器
AFTER/BEFORE是触发的时机
(5)触发器类型
[例5.21]当对表SC的Grade属性进行修改时,若分数增加了10%则将此次操作记录到下面表中:
SC_U(Sno,Cno,Oldgrade,Newgrade)
其中Oldgrade是修改前的分数,Newgrade是修改后的分数。
CREATE TRIGGER SC_T
AFTER UPDATE OF Grade ON SC
REFERENCING
OLD row AS OldTuple,
NEW row AS 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)
[例5.22] 将每次对表Student的插入操作所增加的学生个数记录到表StudentInsertLog中。
CREATE TRIGGER Student_Count
AFTER INSERT ON Student
/*指明触发器激活的时间是在执行INSERT后*/
REFERENCING
NEW TABLE AS DELTA
FOR EACH STATEMENT
/*语句级触发器, 即执行完INSERT语句后下面的触发动作体才执行一次*/
INSERT INTO StudentInsertLog (Numbers)
SELECT COUNT(*) FROM DELTA
[例5.23] 定义一个BEFORE行级触发器,为教师表Teacher定义完整性规则“教授的工资不得低于4000元,如果低于4000元,自动改为4000元”。
CREATE TRIGGER Insert_Or_Update_Sal
BEFORE INSERT OR UPDATE ON Teacher
/*触发事件是插入或更新操作*/
FOR EACH ROW /*行级触发器*/
BEGIN /*定义触发动作体,是PL/SQL过程块*/
IF (new.Job='教授') AND (new.Sal < 4000)
THEN new.Sal :=4000;
END IF;
END;
例子
(1)定义一个before级触发器
--创建insert update 触发器
create trigger Insert_Or_Update ON girlfriend
after insert,update
as begin
update girlfriend set girlfriendSalary = 100 where girlfriendSalary<100;
end
插入数据
insert into girlfriend([stuname],[girlfriendName],[girlfriendSalary],[girlfriendAge],[girlfriendPhone]) values('李勇','花花',10,14,12345);
insert into girlfriend([stuname],[girlfriendName],[girlfriendSalary],[girlfriendAge],[girlfriendPhone]) values('李2勇','花花1',101,14,12345);
insert into girlfriend([stuname],[girlfriendName],[girlfriendSalary],[girlfriendAge],[girlfriendPhone]) values('李3勇','花花2',15,14,12345);
触发器的执行,是由触发事件激活的,并由数据库服务器自动执行
删除触发器的SQL语法
DROP TRIGGER <触发器名> ON <表名>;
触发器必须是一个已经创建的触发器,并且只能由具有相应权限的用户删除。