Mysql課堂筆記4-完整性約束
阿新 • • 發佈:2018-12-20
本文參照UESTC資料庫課程整理總結而成
完整性約束
資料庫完整性概述
- 完整性約束是加在資料庫模式上的一個具體條件,它規定什麼樣的資料能夠儲存到資料庫系統中。 例如:
學生的年齡必須是整數,取值範圍為14--29;
學生的性別只能是“男”或“女”;
學生的學號一定是唯一的;
學生所在的系必須是學校開設的系;
- 資料完整性與安全性的區別
資料的完整性是為了防止資料庫中存在不符合語義的資料,防止錯誤資料的輸入和輸出所造成的無效操作和錯誤結果。
資料的安全性是防止非法使用者的非法操作所造成的對資料庫的惡意破壞。
前者更重點關注使用者的輸入檢查是否符合表的規定,後者在於防止非法使用者對資料庫的所有破壞操作。
完整性約束的分類
1.按照完整性越蘇條件作用的物件
- 型別約束
- 屬性約束
- 關係變數約束
- 資料庫約束
2. 按照完整性約束時宣告的位置
- 列級約束
- 表級約束
3. 兩種狀態:
- 靜態: 對靜態物件的約束是反映資料庫狀態合理性的約束
- 動態: 對動態物件的約束是反映資料庫狀態變遷的約束,新舊值之間滿足的約束
完整性約束的定義
Primary Key約束(約束哪個屬性是主鍵)
- 列級約束:
在屬性定義後面直接加上主鍵約束
CREATE TABLE RecipeMaster{ Rno VARCHAR(10) PRIMARY KEY, DGno VARCHAR(10), Rdatetime DATETIME }
- 表級約束:單屬性主鍵
在全部屬性定義完成後單獨定義約束條件
CREATE TABLE Medicine{
Mno VARCHAR(10),
Mname VARCHAR(50) NOT NULL,
Mprice DECIMAL(18,2) NOT NULL,
Munit VARCHAR(10),
Mtype VARCHAR(10),
PRIMARY KEY(Mno)
}
上述為定義的單屬性主鍵,也可以用同樣的方法定義多屬性組合主鍵。
- 表級約束:多屬性組合主鍵
CREATE TABLE RecipeDetail{ Rno VARCHAR(10), Mno VARCHAR(10) NOT NULL, Mamount DECIMAL(18,0), PRIMARY KEY(Rno,Mno) }
UNIQUE約束
PK約束與UQ約束都要求鍵值不能重複。
在介紹UNIQUE約束前,先介紹下PK約束與UQ約束的不同:
- UNIQUE約束定義和PRIMARY KEY約束定義不能在同一屬性上
- PRIMARY KEY要求屬性取值不能為NULL,而UNIQUE允許屬性取空值,允許多個空值同時存在
- 理論上PK約束是真正的主鍵約束
- 在一個關係中,PRIMARY KEY只有一個,而UNIQUE可以宣告多個
可以說,primary key是特殊的unique key。
- 列級約束
CREATE TABLE Dept{
DeptNo VARCHAR(10) PRIMARY KEY,
DeptName VARCHAR(50) UNIQUE,
ParentDeptNo VARCHAR(10),
Manager VARCHAR(10)
}
- 表級約束
CREATE TABLE Dept{
DeptNo VARCHAR(10),
DeptName VARCHAR(50) ,
ParentDeptNo VARCHAR(10),
Manager VARCHAR(10),
PRIMARY KEY(DeptNo),
UNIQUE(DeptName )
}
在定義了UNIQUE,PRIMARY KEY 約束的屬性上建立索引是十分必要的,它可以使約束的檢查執行起來更有效。
- 索引物件約束
CREATE UNIQUE INDEX deptname_index ON dept(DeptName)
NOT NULL約束
一般用於列級約束
例如:
CREATE TABLE Diagnosis{
DGno VARCHAR(10) PRIMARY KEY,
Pno VARCHAR(10) NOT NULL,
Dno VARCHAR(10) NOT NULL,
Symptom VARCHAR(100),
Diagnosis VARCHAR(100),
DGtime DATETIME,
Rfee DECIMAL(18,2) NOT NULL
}
CHECK約束(在SQL Server中不支援該功能,sqlite中支援)
檢查鍵值是否符合一些具體要求
比如性別是不是男女/年齡是不是在0-60之間
舉例如下:
- 表級約束
CREATE TABLE Doctor{
Dno VARCHAR(10),
Dname VARCHAR(50) NOT NULL,
Dsex VARCHAR(2),
Dage INT,
Ddeptno VARCHAR(10),
Dlevel VARCHAR(50),
Dsalary DECIMAL(18,2),
PRIMARY KEY(Dno),
CHECK( Dsex IN (‘男’, ‘女’)),
CHECK( Dage > 0 AND Dage <60)
}
- 域物件約束
CREATE DOMAIN rfee DECIMAL(18,2)
CONSTRAINT Doctor CHECK(Dage >0)
- SQL條件約束
CREATE TABLE RecipeDetail{
Rno VARCHAR(10),
Mno VARCHAR(10) NOT NULL,
Mamount DECIMAL(18,0),
PRIMARY KEY(Rno,Mno),
CHECK (Mno IN (SELECT Mno FROM Medicine))
}
FK外來鍵約束
格式:foreign key(欄位名)references 其他表(欄位名)
作用:欄位的值必須是其他表中的某個對應的欄位,不能隨便輸入。
- 列級約束
CREATE TABLE Doctor{
Dno VARCHAR(10),
Dname VARCHAR(50) NOT NULL,
Dsex VARCHAR(2),
Dage INT,
Ddeptno VARCHAR(10) REFERENCES Dept(DeptNo),
Dlevel VARCHAR(50),
Dsalary DECIMAL(18,2),
PRIMARY KEY(Dno),
CHECK( Dsex IN ('男', '女'))
}
- 表級約束
CREATE TABLE RecipeDetail{
Rno VARCHAR(10),
Mno VARCHAR(10) NOT NULL,
Mamount DECIMAL(18,0),
PRIMARY KEY(Rno,Mno),
FOREIGN KEY(Mno)REFERENCES Medicine(Mno)
}
域約束
- 通過CREATE DOMAIN可以定義一個新的域;
- 通過對域進行約束可以達到對屬性列取值的約束;
- SQL92用一個特殊的關鍵字VALUE表示域的一個值。
- 統一約束,便於修改。
定義域:
CREATE DOMAIN SexVal CHAR(2)
CHECK (VALUE IN('男', '女'));
使用域:
CREATE TABLE Patient{
Pno VARCHAR(10),
Pname VARCHAR(50) NOT NULL,
Psex SexVal,-- 這裡可以看出域的實質(屬性定義+約束)
Page INT,
Pino VARCHAR(50),
Pid VARCHAR(18),
PRIMARY KEY(Pno)}
斷言
格式:
CREATE ASSERTION <斷言名> CHECK<謂詞>
示例
Create assertion salarycheck check(
Not exists(
Select * from Doctor x
Where Dsalary >= some ( select Dsalary from Doctor y
Where x.Deptno=y.Deptno and y.Dno =(
Select Manager from Dept
Where x.Deptno =Dept.Deptno)
)
)
參照完整性的保證
我們定義RecipeDetail中FOREIGN KEY(Mno)REFERENCES Medicine(Mno),在RecipeDetail中新增、修改Mno分量,在Medicine中刪除、修改Mno的分量值,則違背了完整性約束。這時應該怎麼辦呢?
受限策略(RESTRICTED)
- 系統預設策略
- 當出現違背參照完整性規則的更新操作請求時,系統拒絕執行該操作
置空策略(SET-NULL)
- 依照參照完整性規則,外碼是可以取空值的。
- 但具體能否取空值,要根據應用環境的語義來定。
示例:
CREATE TABLE Doctor{
Dno VARCHAR(10) PRIMARY KEY,
Dname VARCHAR(50) NOT NULL,
Dsex VARCHAR(2),
Dage INT,
Ddeptno VARCHAR(10) REFERENCES Dept(DeptNo)
ON DELETE SET NULL ,
Dlevel VARCHAR(50),
Dsalary DECIMAL(18,2)
}
級聯策略(CASCADE)
- 不用拒絕使用者操作請求的處理方式。
- 連帶處理參照資料。
示例:
CREATE TABLE RecipeDetail{
Rno VARCHAR(10),
Mno VARCHAR(10) NOT NULL,
Mamount DECIMAL(18,0),
PRIMARY KEY(Rno,Mno),
FOREIGN KEY(Mno)REFERENCES Medicine(Mno)
ON DELETE CASCADE
ON UPDATE CASCADE
}
完整性約束的修改
我們想要對約束有更多的需求,想在任何時候都可以新增、修改、刪除約束。
而為了對約束進行修改、刪除,有必要對約束命名。
約束命名:CONSTRAINT關鍵字後跟約束名稱
示例:
CREATE TABLE RecipeDetail{
Rno VARCHAR(10),
Mno VARCHAR(10) CONSTRAINT notnullMno NOT NULL,
Mamount DECIMAL(18,0),
CONSTRAINT pkRecipeDetailRnoMno PRIMARY KEY(Rno,Mno),
CONSTRAINT fkRecipeDetailMnoMedicine FOREIGN KEY(Mno)REFERENCES Medicine(Mno)
ON DELETE CASCADE
ON UPDATE CASCADE
}
- 刪除約束
ALTER TABLE RecipeDetail DROP CONSTRAINT pkRecipeDetailRnoMno
- 增加約束
ALTER TABLE RecipeDetail ADD CONSTRAINT pkRecipeDetailRnoMno PRIMARY KEY(Rno,Mno);
ALTER TABLE RecipeDetail ADD CONSTRAINT fkRecipeDetailMnoMedicine FOREIGN KEY(Mno)REFERENCES Medicine (Mno);
ALTER TABLE Doctor ADD CONSTRAINT checkPsex CHECK( Psex IN ('男', '女'));
ALTER DOMAIN rfee DECIMAL(18,2) DROP CONSTRAINT rfee_test;