程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> Oracle數據庫 >> Oracle教程 >> 數據庫復習3——數據庫完整性

數據庫復習3——數據庫完整性

編輯:Oracle教程

數據庫復習3——數據庫完整性


數據庫復習


CH5 完整性

5.1 完整性約束

數據庫完整性是指數據庫中數據在邏輯上的一致性、正確性、有效性和相容性,那麼完整性約束就是指用戶插入、修改和刪除操作時,DBMS為了保證數據庫邏輯上的一致性、正確性、有效性和相容性所必需要檢查的約束條件

C.J.Date在《An Introduction to Database Systems》一書中描述了四種完整性約束:

類型約束 屬性約束 關系變量約束 數據庫約束

C.J.Date提出的理論多半是建立在他自創的Tutorial D這個概念型數據庫操作語言上的,下面的描述也是基於Tutorial D,注意不要和SQL混淆

(1)類型約束

類型約束是關於自定義類型的種類(或就是數域)以及值大小的約束,例如我們自定類型weight是實數類型且要求weight必須大於0,那麼用Tutorial D定義一個類型約束如下:

TYPE weight POSSREP(RATIONAL) CONSTRAINT the_weight(weight) > 0.0;

POSSREP是possible representation(可能的表達方式),RATIONAL是有理數,the_加weight(前面提到過這是C.J.Date提出的對類型的操作符號,表示取值)weight作用於weight表示取值

(2)屬性約束

屬性約束就是定義關系時定義屬性的類型產生的隱式約束,Tutorial D定義一個關系如下:

VAR S BASE RELATION(S# S#, status integer, city char);

比如上例的status就需要隱式遵守類型integer的類型約束

(3)關系變量約束

關系變量約束是對關系中元組的約束,如限定在倫敦的供應商狀態一定是20:

Constraint sc1 is_empty(S where city = 'London' and status ~= 20);

關系變量約束總是立即檢查的

(4)數據庫約束

關系變量約束是針對單個關系變量內部屬性的約束(可以把關系變量就理解為關系/表),若約束涉及多個關系變量,則稱之為數據庫約束

如下的數據庫約束,限定零件商的個數必須等於供應表中零件商的個數:

Constraint dbc1 count(SP(p#)) = count(P(p#));

(5)約束設計的黃金准則(Golden Rule)

關於Golden Rule,C.J.Date在這裡想要表達的是我們定義的所有完整性約束都稱之為內部約束,用戶和DBMS都很清楚,比如體重必須大於0

然而我們設計的系統還有很多其他的外部約束,比如說我的體重是69.5,那麼可以插入一個元組(jcguo, 69.5),但是插入(jcguo, 100.5)說我是個大胖子DBMS也是允許的,但這違反了現實世界的約束

這屆涉及到之前在完整性定義中包括的正確性,C.J.Date認為這部分的完整性應該由用戶或者說DBA在數據庫外部限定,而不是交給DBMS

5.2 鍵Key

數據庫中可以定義一種特殊的完整性約束——鍵(key,或者有時也翻譯為碼,我叫鍵比較順口)

(1)各種鍵的定義

我們先來弄清楚各種鍵的定義:

super key:超鍵,在關系中能夠唯一標識元組的屬性集 candidate key:候選鍵(一般叫候選碼),不含有多余屬性/不可規約超鍵 primary key:主鍵,用戶選做唯一表識元組的候選鍵,主鍵不能為null alternate key:可選鍵,候選鍵中除了主鍵以外,沒有被用戶選中的候選鍵 foreign key:外鍵,是依賴於其他關系用於保證數據庫邏輯完整性的約束

前四個key都很好理解,下面著重理解一下外鍵

(2)外鍵

關系R1聲明在屬性a1上創建外鍵FK,那麼有:

這個外鍵FK必須reference(引用or以來)於另一個關系R2的候選鍵CK(一般reference另一個關系的主鍵,設CK創建於屬性a2上) 這個reference的作用就是保證R1中屬性a1中出現的值全部都在R2的a2中出現(完整性約束)

注意,外鍵FK並不要求R2中屬性a2(CK)中出現的值都必須在R1中屬性a1中出現,只是說單方面的約束:一旦在FK中出現則必須在CK中出現

外鍵還有另一個最重要的特性:referential action(關聯動作),關聯動作是一個隱式的特殊的觸發器(每當滿足出發條件時都會出發的動作集合)

下面在講SQL完整性時會詳細闡述SQL所支持的關聯動作

5.3 SQL完整性

再次強調之前我們復習的所有完整性都是抽象性的概念,需要理解,那麼這一小節SQL完整性則需要記憶了

(1)域約束

域約束(Domain Constraints)是SQL中對屬性取值范圍的約束,SQL聲明域約束是在create table時完成的,支持帶名稱的顯式約束聲明以及不帶名稱的便捷約束聲明兩種方式:

create table Student(
    S# char(10),
    name char(20),
    gender char(1),
    constraint gc check (gender in ('F', 'M'))  
);

和下面等價:

create table Student(
    S# char(10),
    name char(20),
    gender char(1) check (gender in ('F', 'M'))
);

check從句中可以使用常用的比較關系操作符號,也可以使用in構造復合語句

給約束命名是為了某些特殊情況我們需要對約束進行修改,見我另外一篇博文:

另外SQL支持對已聲明的table添加約束,使用alter table語句,本課程暫不要求

(2)主鍵

SQL主鍵聲明也是在create table時聲明的,聲明主鍵也有兩種方式(顯式和便捷式,顯式主鍵不需要名字,因為一個關系/表只能有一個主鍵):

create table Student(
    S# char(10),
    name char(20),
    gender char(1) check (gender in ('F', 'M')),
    primary key (S#)
);

等價於:

create table Student(
    S# char(10) primary key,
    name char(20),
    gender char(1) check (gender in ('F', 'M'))
);

需要注意的是主鍵不能為空,不能插入一條不包含主鍵/主鍵為null的元組

primary key也可以作用於多個屬性,如同前面概念講解中所提到的,如何設計依需求而定

(3)unique

SQL中實現候選碼使用unique約束,一個關系可以有多條unique約束

這句話翻譯自老師ppt,個人覺得需要補充:

SQL中淡化了candidate key的概念 unique約束不僅可以實現候選碼,也可以實現超碼,也就是它沒有不可約的限制

聲明uniqle約束和主鍵類似,舉例略

(4)外鍵

Foreign key之前留了個坑,這裡直接舉例吧:

create table Dept(
    D# char(3) primary key,
    name char(20),
    type char(20) check (type in ('engineering', 'science', 'business'))
);

先創建了一個table Dept是系的關系,它的主鍵是D#,再創建一個Student表,它的屬性D#上聲明了一個引用Dept(D#)的外鍵:

create table Student(
    S# char(10) primary key,
    name char(20),
    gender char(1) check (gender in ('F', 'M')),
    D# char(3) foreign key references Dept(D#)
);

上面的聲明等價於:

create table Student(
    S# char(10) primary key,
    name char(20),
    gender char(1) check (gender in ('F', 'M')),
    D# char(3),
    contraint dfk foreign key references Dept(D#)
);

這裡外鍵的約束就是限制學生表裡的D#必須在系表裡的D#中出現,那麼很容易想到一個問題:如果USTC新任校長萬老大把11系拆了,也就是系表裡把D#為’011’的元組刪除了的話,那我們11系的學生在Student表裡的tuples不就不滿足外鍵約束了嗎

這時候就需要引入關聯動作,關聯動作分為級聯(Cascade)動作和設置(Set)動作

1.級聯動作

級聯動作就是一系列的主鍵-外鍵-主鍵-外鍵-…約束引用鏈條的後端的某個主鍵delete或update,會產生(自動的,觸發器)沿引用鏈條從後往前的一系列外鍵的delete或update操作

例如我們聲明一個D#的刪除級聯,即:

create table Student(
    S# char(10) primary key,
    name char(20),
    gender char(1) check (gender in ('F', 'M')),
    D# char(3) foreign key references Dept(D#) on delete cascade
);

此時刪除11系,那麼根據級聯動作定義,所有11系的學生都被刪除,因為Student表通過外鍵引用了Dept表的主鍵

再假設Dept表引用了一個學校編號U#的外鍵,它是一個University表的主鍵,此時構成了一個引用鏈條,若這個University表刪除了USTC的條目,那麼根據級聯動作定義USTC的11系,11系的學生都將被自動刪除

級聯動作也可以是on update cascade,比如11系改系別號為1系了,那麼11系的學生能夠自動的把D#改成‘001’

DBMS處理級聯動作是按事務來處理的,若在引用鏈條中某一個部分的級聯動作違反了其他的完整性約束,那麼整個修改動作都會被回滾(事務的概念),即修改失敗

ppt中寫道:

Referential integrity is only checked at the end of a transaction
–– Intermediate steps are allowed to violate referential integrity provided later steps remove the violation, otherwise it would be impossible to create some database states, e.g. insert two tuples whose foreign keys point to each other

很不幸的是在實驗中我發現這條規則MySQL適用但Oracle並不適用(至少在PL/SQL中)

SQL支持一個外鍵同時有一個刪除級聯和一個更新級聯

2.設置動作

設置動作比較好理解:

on delete set null on delete set default

5.4 斷言和觸發器

(1)斷言

SQL還支持使用斷言(Assertion)在關系外部定義數據庫必須滿足的條件,語法為:

create assertion  check 
;

Assertion有點類似於C.J.Date定義的數據庫約束,可以針對單表或多表

ppt中一個復雜的例子,限定每個部門的工資總和必須小於d1部門的工資總和:

create assertion sac check(
    not exists(
        select * from EMP e2 
        where (select sum(sal) from EMP e1 where e1.d# = e2.d#) 
            >= (select sum(sal) from EMP where d# = 'd1')
    )
);

PS:我咋覺得第一個where後面要加d# ~= 'd1' and呢?

(2)觸發器

觸發器定義了數據庫狀態改變(元組修改)時需要自動執行的一系列動作,定義觸發器包括兩個要點:

觸發條件 執行動作

觸發器還有幾個重要屬性:

事前觸發或事後觸發 行觸發還是整體觸發

事前觸發或事後觸發比較好理解,行觸發還是整體觸發是指的是一條update或delete時若涉及多個元組的修改,是整體觸發一次還是每個元組都觸發一次

還是舉例說明,下面是我在Oracle上創建的行觸發器:

create or replace trigger countStud
after delete or insert or update on Stud
for each row
begin
      update Dept set S_count =  S_count+1 where D# = :new.D#;
      update Dept set S_count =  S_count-1 where D# = :old.D#;
end;

這是一個用來統計系裡人數的觸發器(或者說叫做保證系裡人數完整性的觸發器),分點說明:

after delete or insert or update on Stud指定了觸發器的條件和觸發時機:當Stud表有刪除、插入或更新操作之後觸發 for each row聲明這是一個行觸發器,按行觸發 begin和end包體裡指定了觸發器的動作

至於其中的:new和是:old保留變量,對應刪除、插入或更新三個操作他們有如下含義:

 

含義 insert update delete :new 新插入的元組 更新後的元組 null :old null 更新前的元組 刪除的元組

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved