國際慣例:本章主要的內容一覽:
概述
數據庫的完整性是指數據的正確性和相容性。正確性是指數據符合現實世界語義,符合當前的情況,相容性是指數據庫同一對象在不同關係表中的數據是符合邏輯的。
實體完整性
定義實體完整性
關係模型的實體完整性是在創建表的時候用主碼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 <表名>
觸發器功能強大,但是因爲在每次訪問一個表時,都可能觸發一個觸發器,這樣會影響系統的性能,所以需要謹慎使用。