完整性約束的作用在于保證授權(quán)用戶對數(shù)據(jù)庫所做的修改不會破壞數(shù)據(jù)的一致性?;蛘哒f,防止的是對數(shù)據(jù)的意外破壞。
單個關(guān)系的約束
一般而言,約束是在創(chuàng)建表的時候生成,例如我們在之前的《SQL——SQL數(shù)據(jù)定義》
有這樣的例子
CREATE TABLE department(
dept_name VARCHAR(20),
building VARCHAR(15),
budget NUMERIC(12,2),
PRIMARY KEY (dept_name)
);
完整性約束有三種:
- not null
- unique
- check(<P>)
not null 約束
not null 約束是使得被約束的屬性的值不能 (禁止)為空值。例如,我們要將dept_name設(shè)置為非空:
dept_name VARCHAR(20) NOT NULL
不過在這里dept_name也可以不加not null,因為這里not null 是主碼,是默認不能為空。
unique 約束
通式:
unique<A1,A2,...An>
unique聲明<A1,A2,...An>是一個候選碼,即在關(guān)系中沒有兩個元祖在所有這些列出的屬性上取值相同,但可以同時為空。因為空值不等于任何值。
示例:
unique(building)
#或者
unique(building,budget)
#或者(該方法只適用于約束單個屬性)
building unique
check子句
check子句自定一個謂詞P,關(guān)系中的每一個元組都必須滿足謂詞P,例如:
#保證department中的budget>0,那么可以這樣寫:
CREATE TABLE department(
dept_name VARCHAR(20),
building VARCHAR(15),
budget NUMERIC(12,2),
PRIMARY KEY (dept_name),
CHECK(budget>0)
);
#保證section表的semester是集合中的字符串
check(semester in{'fall','spring','winter','summer'})
參照完整性
我們常常希望保證在一個關(guān)系中給定屬性集上的取值也在另一關(guān)系的特定屬性集的取值中出現(xiàn),這種情況稱為參照完整性。
我們令關(guān)系r1和關(guān)系r2的屬性集為R1和R2,主碼分別為K1和K2。如果要求對r2中任意元組t2,均存在r1中元組t1使得t.K1=t2.α,我們稱R2的子集α為參照關(guān)系r1中K1的外碼。
這種要求稱為參照完整性約束或者子集依賴。
SQL中 外碼參照的是被參照表中的主碼屬性,可用reference指定,指定的屬性列表必須被聲明為被參照關(guān)系的候選碼,即被primary或者unique約束的屬性。
例如
#dept_name是外碼,department是被參照關(guān)系,department中dept_name為主碼
dept_name varchar(20)reference department
#或者寫成下面的形式
dept_name varchar(20),
foreign key(dept_name) reference department(dept_name)
復(fù)雜check條件和斷言
復(fù)雜check條件
SQL標準定義,check子句中的謂詞可以是包含子查詢的任意謂詞。如果一個數(shù)據(jù)庫實現(xiàn)支持在check子句中出現(xiàn)子查詢(如果不支持就不能這樣使用),我們就可以在關(guān)系section上聲明如下所示的參照完整性約束:
check (time_slot_id in(select time_slot_id from time_slot))
像這樣的復(fù)雜check條件在我們希望確保數(shù)據(jù)完整性的時候是很有用的,但是其檢測開銷可能會很大。例如,check子句中的謂詞不僅需要在section關(guān)系發(fā)生更新時計算,而且也可能在time_slot關(guān)系發(fā)生更新時檢測,因為time_slot在子查詢中被引用了。
斷言
一個斷言(assertion)就是謂詞,它表達了我們希望數(shù)據(jù)庫總能滿足的一個條件。域約束和參照完整性約束是斷言的特殊形式。前面幾種約束(像not null等),有些約束不能僅用這幾種約束來表達。例如:
對于student關(guān)系中的每個元組,它在屬性tol_cred上的取值必須等于該學(xué)生所成功修完課程的學(xué)分總和。
每位教師不能在同一學(xué)期的同一時間段在兩個不同的教室授課。
這是需用斷言來實現(xiàn),斷言為如下的形式
create assertion <assertion-name> check <predicate>;
SQL不提供“for all X,P(X)”,即不提供對于任意x,使得P(x)的結(jié)構(gòu),那么我們只能通過等價的“not exists X such that not P(x)”,即不存在X,使得非P(x)。對于第一個例子可以這樣實現(xiàn):
CREATE ASSERTION credit_earned_constraint CHECK (
NOT exists(
SELECT id
FROM student
WHERE tol_cred<>(
SELECT sum(credits)
FROM takes NATURAL JOIN course
WHERE student.id = takes.id
AND grade IS NOT NULL AND grade>=60
)
)
);
當創(chuàng)建斷言時,系統(tǒng)要檢測其有效性。如果斷言有效,則今后只有不破壞斷言的數(shù)據(jù)庫修改才被允許。如果斷言較復(fù)雜,則檢測會帶來相當大的開銷,應(yīng)該注意。