東西很多 要慢慢看。。大概整合了三篇文章
設計范式(范式,數據庫設計范式,數據庫的設計范式)是符合某一種級別的關(guān)系模式的集合。構造數據庫必須遵循一定的規則。在關(guān)系數據庫中,這種規則就是范式。關(guān)系數據庫中的關(guān)系必須滿(mǎn)足一定的要求,即滿(mǎn)足不同的范式。目前關(guān)系數據庫有六種范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、第四范式(4NF)、第五范式(5NF)和第六范式(6NF)。滿(mǎn)足最低要求的范式是第一范式(1NF)。在第一范式的基礎上進(jìn)一步滿(mǎn)足更多要求的稱(chēng)為第二范式(2NF),其余范式以次類(lèi)推。一般說(shuō)來(lái),數據庫只需滿(mǎn)足第三范式(3NF)就行了。下面我們舉例介紹第一范式(1NF)、第二范式(2NF)和第三范式(3NF)。
在創(chuàng )建一個(gè)數據庫的過(guò)程中,范化是將其轉化為一些表的過(guò)程,這種方法可以使從數據庫得到的結果更加明確。這樣可能使數據庫產(chǎn)生重復數據,從而導致創(chuàng )建多余的表。范化是在識別數據庫中的數據元素、關(guān)系,以及定義所需的表和各表中的項目這些初始工作之后的一個(gè)細化的過(guò)程。
下面是范化的一個(gè)例子
Customer Item purchased Purchase price
Thomas Shirt $40
Maria Tennis shoes $35
Evelyn Shirt $40
Pajaro Trousers $25
如果上面這個(gè)表用于保存物品的價(jià)格,而你想要刪除其中的一個(gè)顧客,這時(shí)你就必須同時(shí)刪除一個(gè)價(jià)格。范化就是要解決這個(gè)問(wèn)題,你可以將這個(gè)表化為兩個(gè)表,一個(gè)用于存儲每個(gè)顧客和他所買(mǎi)物品的信息,另一個(gè)用于存儲每件產(chǎn)品和其價(jià)格的信息,這樣對其中一個(gè)表做添加或刪除操作就不會(huì )影響另一個(gè)表。
關(guān)系數據庫的幾種設計范式介紹
1 第一范式(1NF)
在任何一個(gè)關(guān)系數據庫中,第一范式(1NF)是對關(guān)系模式的基本要求,不滿(mǎn)足第一范式(1NF)的數據庫就不是關(guān)系數據庫。
所謂第一范式(1NF)是指數據庫表的每一列都是不可分割的基本數據項,同一列中不能有多個(gè)值,即實(shí)體中的某個(gè)屬性不能有多個(gè)值或者不能有重復的屬性。如果出現重復的屬性,就可能需要定義一個(gè)新的實(shí)體,新的實(shí)體由重復的屬性構成,新實(shí)體與原實(shí)體之間為一對多關(guān)系。在第一范式(1NF)中表的每一行只包含一個(gè)實(shí)例的信息。例如,對于圖3-2 中的員工信息表,不能將員工信息都放在一列中顯示,也不能將其中的兩列或多列在一列中顯示;員工信息表的每一行只表示一個(gè)員工的信息,一個(gè)員工的信息在表中只出現一次。簡(jiǎn)而言之,第一范式就是無(wú)重復的列。
2 第二范式(2NF)
第二范式(2NF)是在第一范式(1NF)的基礎上建立起來(lái)的,即滿(mǎn)足第二范式(2NF)必須先滿(mǎn)足第一范式(1NF)。第二范式(2NF)要求數據庫表中的每個(gè)實(shí)例或行必須可以被惟一地區分。為實(shí)現區分通常需要為表加上一個(gè)列,以存儲各個(gè)實(shí)例的惟一標識。如圖3-2 員工信息表中加上了員工編號(emp_id)列,因為每個(gè)員工的員工編號是惟一的,因此每個(gè)員工可以被惟一區分。這個(gè)惟一屬性列被稱(chēng)為主關(guān)鍵字或主鍵、主碼。
第二范式(2NF)要求實(shí)體的屬性完全依賴(lài)于主關(guān)鍵字。所謂完全依賴(lài)是指不能存在僅依賴(lài)主關(guān)鍵字一部分的屬性,如果存在,那么這個(gè)屬性和主關(guān)鍵字的這一部分應該分離出來(lái)形成一個(gè)新的實(shí)體,新實(shí)體與原實(shí)體之間是一對多的關(guān)系。為實(shí)現區分通常需要為表加上一個(gè)列,以存儲各個(gè)實(shí)例的惟一標識。簡(jiǎn)而言之,第二范式就是非主屬性必須依賴(lài)于整個(gè)主關(guān)鍵字。
3 第三范式(3NF)
滿(mǎn)足第三范式(3NF)必須先滿(mǎn)足第二范式(2NF)。簡(jiǎn)而言之,第三范式(3NF)要求一個(gè)數據庫表中不包含已在其它表中已包含的非主關(guān)鍵字信息。例如,存在一個(gè)部門(mén)信息表,其中每個(gè)部門(mén)有部門(mén)編號(dept_id)、部門(mén)名稱(chēng)、部門(mén)簡(jiǎn)介等信息。那么在圖3-2的員工信息表中列出部門(mén)編號后就不能再將部門(mén)名稱(chēng)、部門(mén)簡(jiǎn)介等與部門(mén)有關(guān)的信息再加入員工信息表中。如果不存在部門(mén)信息表,則根據第三范式(3NF)也應該構建它,否則就會(huì )有大量的數據冗余。簡(jiǎn)而言之,第三范式就是屬性不依賴(lài)于其它非主屬性。
數據庫設計三大范式應用實(shí)例剖析
數據庫的設計范式是數據庫設計所需要滿(mǎn)足的規范,滿(mǎn)足這些規范的數據庫是簡(jiǎn)潔的、結構明晰的,同時(shí),不會(huì )發(fā)生插入(insert)、刪除(delete)和更新(update)操作異常。反之則是亂七八糟,不僅給數據庫的編程人員制造麻煩,而且面目可憎,可能存儲了大量不需要的冗余信息。
設計范式是不是很難懂呢?非也,大學(xué)教材上給我們一堆數學(xué)公式我們當然看不懂,也記不住。所以我們很多人就根本不按照范式來(lái)設計數據庫。
實(shí)質(zhì)上,設計范式用很形象、很簡(jiǎn)潔的話(huà)語(yǔ)就能說(shuō)清楚,道明白。本文將對范式進(jìn)行通俗地說(shuō)明,并以筆者曾經(jīng)設計的一個(gè)簡(jiǎn)單論壇的數據庫為例來(lái)講解怎樣將這些范式應用于實(shí)際工程。
范式說(shuō)明
第一范式(1NF):數據庫表中的字段都是單一屬性的,不可再分。這個(gè)單一屬性由基本類(lèi)型構成,包括整型、實(shí)數、字符型、邏輯型、日期型等。
例如,如下的數據庫表是符合第一范式的:
字段1 字段2 字段3 字段4
而這樣的數據庫表是不符合第一范式的:
字段1 字段2 字段3 字段4
字段3.1 字段3.2
很顯然,在當前的任何關(guān)系數據庫管理系統(DBMS)中,傻瓜也不可能做出不符合第一范式的數據庫,因為這些DBMS不允許你把數據庫表的一列再分成二列或多列。因此,你想在現有的DBMS中設計出不符合第一范式的數據庫都是不可能的。
第二范式(2NF):數據庫表中不存在非關(guān)鍵字段對任一候選關(guān)鍵字段的部分函數依賴(lài)(部分函數依賴(lài)指的是存在組合關(guān)鍵字中的某些字段決定非關(guān)鍵字段的情況),也即所有非關(guān)鍵字段都完全依賴(lài)于任意一組候選關(guān)鍵字。
假定選課關(guān)系表為SelectCourse(學(xué)號, 姓名, 年齡, 課程名稱(chēng), 成績(jì), 學(xué)分),關(guān)鍵字為組合關(guān)鍵字(學(xué)號, 課程名稱(chēng)),因為存在如下決定關(guān)系:
(學(xué)號, 課程名稱(chēng)) → (姓名, 年齡, 成績(jì), 學(xué)分)
這個(gè)數據庫表不滿(mǎn)足第二范式,因為存在如下決定關(guān)系:
(課程名稱(chēng)) → (學(xué)分)
(學(xué)號) → (姓名, 年齡)
即存在組合關(guān)鍵字中的字段決定非關(guān)鍵字的情況。
由于不符合2NF,這個(gè)選課關(guān)系表會(huì )存在如下問(wèn)題:
(1) 數據冗余:
同一門(mén)課程由n個(gè)學(xué)生選修,"學(xué)分"就重復n-1次;同一個(gè)學(xué)生選修了m門(mén)課程,姓名和年齡就重復了m-1次。
(2) 更新異常:
若調整了某門(mén)課程的學(xué)分,數據表中所有行的"學(xué)分"值都要更新,否則會(huì )出現同一門(mén)課程學(xué)分不同的情況。
(3) 插入異常:
假設要開(kāi)設一門(mén)新的課程,暫時(shí)還沒(méi)有人選修。這樣,由于還沒(méi)有"學(xué)號"關(guān)鍵字,課程名稱(chēng)和學(xué)分也無(wú)法記錄入數據庫。
(4) 刪除異常:
假設一批學(xué)生已經(jīng)完成課程的選修,這些選修記錄就應該從數據庫表中刪除。但是,與此同時(shí),課程名稱(chēng)和學(xué)分信息也被刪除了。很顯然,這也會(huì )導致插入異常。
把選課關(guān)系表SelectCourse改為如下三個(gè)表:
學(xué)生:Student(學(xué)號, 姓名, 年齡);
課程:Course(課程名稱(chēng), 學(xué)分);
選課關(guān)系:SelectCourse(學(xué)號, 課程名稱(chēng), 成績(jì))。
這樣的數據庫表是符合第二范式的, 消除了數據冗余、更新異常、插入異常和刪除異常。
另外,所有單關(guān)鍵字的數據庫表都符合第二范式,因為不可能存在組合關(guān)鍵字。
第三范式(3NF):在第二范式的基礎上,數據表中如果不存在非關(guān)鍵字段對任一候選關(guān)鍵字段的傳遞函數依賴(lài)則符合第三范式。所謂傳遞函數依賴(lài),指的是如果存在"A → B → C"的決定關(guān)系,則C傳遞函數依賴(lài)于A(yíng)。因此,滿(mǎn)足第三范式的數據庫表應該不存在如下依賴(lài)關(guān)系:
關(guān)鍵字段 → 非關(guān)鍵字段x → 非關(guān)鍵字段y
假定學(xué)生關(guān)系表為Student(學(xué)號, 姓名, 年齡, 所在學(xué)院, 學(xué)院地點(diǎn), 學(xué)院電話(huà)),關(guān)鍵字為單一關(guān)鍵字"學(xué)號",因為存在如下決定關(guān)系:
(學(xué)號) → (姓名, 年齡, 所在學(xué)院, 學(xué)院地點(diǎn), 學(xué)院電話(huà))
這個(gè)數據庫是符合2NF的,但是不符合3NF,因為存在如下決定關(guān)系:
(學(xué)號) → (所在學(xué)院) → (學(xué)院地點(diǎn), 學(xué)院電話(huà))
即存在非關(guān)鍵字段"學(xué)院地點(diǎn)"、"學(xué)院電話(huà)"對關(guān)鍵字段"學(xué)號"的傳遞函數依賴(lài)。
它也會(huì )存在數據冗余、更新異常、插入異常和刪除異常的情況,讀者可自行分析得知。
把學(xué)生關(guān)系表分為如下兩個(gè)表:
學(xué)生:(學(xué)號, 姓名, 年齡, 所在學(xué)院);
學(xué)院:(學(xué)院, 地點(diǎn), 電話(huà))。
這樣的數據庫表是符合第三范式的,消除了數據冗余、更新異常、插入異常和刪除異常。
鮑依斯-科得范式(BCNF):在第三范式的基礎上,數據庫表中如果不存在任何字段對任一候選關(guān)鍵字段的傳遞函數依賴(lài)則符合第三范式。
假設倉庫管理關(guān)系表為StorehouseManage(倉庫ID, 存儲物品ID, 管理員ID, 數量),且有一個(gè)管理員只在一個(gè)倉庫工作;一個(gè)倉庫可以存儲多種物品。這個(gè)數據庫表中存在如下決定關(guān)系:
(倉庫ID, 存儲物品ID) →(管理員ID, 數量)
(管理員ID, 存儲物品ID) → (倉庫ID, 數量)
所以,(倉庫ID, 存儲物品ID)和(管理員ID, 存儲物品ID)都是StorehouseManage的候選關(guān)鍵字,表中的唯一非關(guān)鍵字段為數量,它是符合第三范式的。但是,由于存在如下決定關(guān)系:
(倉庫ID) → (管理員ID)
(管理員ID) → (倉庫ID)
即存在關(guān)鍵字段決定關(guān)鍵字段的情況,所以其不符合BCNF范式。它會(huì )出現如下異常情況:
(1) 刪除異常:
當倉庫被清空后,所有"存儲物品ID"和"數量"信息被刪除的同時(shí),"倉庫ID"和"管理員ID"信息也被刪除了。
(2) 插入異常:
當倉庫沒(méi)有存儲任何物品時(shí),無(wú)法給倉庫分配管理員。
(3) 更新異常:
如果倉庫換了管理員,則表中所有行的管理員ID都要修改。
把倉庫管理關(guān)系表分解為二個(gè)關(guān)系表:
倉庫管理:StorehouseManage(倉庫ID, 管理員ID);
倉庫:Storehouse(倉庫ID, 存儲物品ID, 數量)。
這樣的數據庫表是符合BCNF范式的,消除了刪除異常、插入異常和更新異常。
范式應用
我們來(lái)逐步搞定一個(gè)論壇的數據庫,有如下信息:
(1) 用戶(hù):用戶(hù)名,email,主頁(yè),電話(huà),聯(lián)系地址
(2) 帖子:發(fā)帖標題,發(fā)帖內容,回復標題,回復內容
第一次我們將數據庫設計為僅僅存在表:
用戶(hù)名 email 主頁(yè) 電話(huà) 聯(lián)系地址 發(fā)帖標題 發(fā)帖內容 回復標題 回復內容
這個(gè)數據庫表符合第一范式,但是沒(méi)有任何一組候選關(guān)鍵字能決定數據庫表的整行,唯一的關(guān)鍵字段用戶(hù)名也不能完全決定整個(gè)元組。我們需要增加"發(fā)帖ID"、"回復ID"字段,即將表修改為:
用戶(hù)名 email 主頁(yè) 電話(huà) 聯(lián)系地址 發(fā)帖ID 發(fā)帖標題 發(fā)帖內容 回復ID 回復標題 回復內容
這樣數據表中的關(guān)鍵字(用戶(hù)名,發(fā)帖ID,回復ID)能決定整行:
(用戶(hù)名,發(fā)帖ID,回復ID) → (email,主頁(yè),電話(huà),聯(lián)系地址,發(fā)帖標題,發(fā)帖內容,回復標題,回復內容)
但是,這樣的設計不符合第二范式,因為存在如下決定關(guān)系:
(用戶(hù)名) → (email,主頁(yè),電話(huà),聯(lián)系地址)
(發(fā)帖ID) → (發(fā)帖標題,發(fā)帖內容)
(回復ID) → (回復標題,回復內容)
即非關(guān)鍵字段部分函數依賴(lài)于候選關(guān)鍵字段,很明顯,這個(gè)設計會(huì )導致大量的數據冗余和操作異常。
我們將數據庫表分解為(帶下劃線(xiàn)的為關(guān)鍵字):
(1) 用戶(hù)信息:用戶(hù)名,email,主頁(yè),電話(huà),聯(lián)系地址
(2) 帖子信息:發(fā)帖ID,標題,內容
(3) 回復信息:回復ID,標題,內容
(4) 發(fā)貼:用戶(hù)名,發(fā)帖ID
(5) 回復:發(fā)帖ID,回復ID
這樣的設計是滿(mǎn)足第1、2、3范式和BCNF范式要求的,但是這樣的設計是不是最好的呢?
不一定。
觀(guān)察可知,第4項"發(fā)帖"中的"用戶(hù)名"和"發(fā)帖ID"之間是1:N的關(guān)系,因此我們可以把"發(fā)帖"合并到第2項的"帖子信息"中;第5項"回復"中的"發(fā)帖ID"和"回復ID"之間也是1:N的關(guān)系,因此我們可以把"回復"合并到第3項的"回復信息"中。這樣可以一定量地減少數據冗余,新的設計為:
(1) 用戶(hù)信息:用戶(hù)名,email,主頁(yè),電話(huà),聯(lián)系地址
(2) 帖子信息:用戶(hù)名,發(fā)帖ID,標題,內容
(3) 回復信息:發(fā)帖ID,回復ID,標題,內容
數據庫表1顯然滿(mǎn)足所有范式的要求;
數據庫表2中存在非關(guān)鍵字段"標題"、"內容"對關(guān)鍵字段"發(fā)帖ID"的部分函數依賴(lài),即不滿(mǎn)足第二范式的要求,但是這一設計并不會(huì )導致數據冗余和操作異常;
數據庫表3中也存在非關(guān)鍵字段"標題"、"內容"對關(guān)鍵字段"回復ID"的部分函數依賴(lài),也不滿(mǎn)足第二范式的要求,但是與數據庫表2相似,這一設計也不會(huì )導致數據冗余和操作異常。
由此可以看出,并不一定要強行滿(mǎn)足范式的要求,對于1:N關(guān)系,當1的一邊合并到N的那邊后,N的那邊就不再滿(mǎn)足第二范式了,但是這種設計反而比較好!
對于M:N的關(guān)系,不能將M一邊或N一邊合并到另一邊去,這樣會(huì )導致不符合范式要求,同時(shí)導致操作異常和數據冗余。
對于1:1的關(guān)系,我們可以將左邊的1或者右邊的1合并到另一邊去,設計導致不符合范式要求,但是并不會(huì )導致操作異常和數據冗余。
結論
滿(mǎn)足范式要求的數據庫設計是結構清晰的,同時(shí)可避免數據冗余和操作異常。這并意味著(zhù)不符合范式要求的設計一定是錯誤的,在數據庫表中存在1:1或1:N關(guān)系這種較特殊的情況下,合并導致的不符合范式要求反而是合理的。
理解數據庫范式
系統是短暫的
數據是永恒的
數 據庫范式是數據庫設計中必不可少的知識,沒(méi)有對范式的理解,就無(wú)法設計出高效率、優(yōu)雅的數據庫。甚至設計出錯誤的數據庫。而想要理解并掌握范式卻并不是那 么容易。教科書(shū)中一般以關(guān)系代數的方法來(lái)解釋數據庫范式。這樣做雖然能夠十分準確的表達數據庫范式,但比較抽象,不太直觀(guān),不便于理解,更難以記憶。
本 文用較為直白的語(yǔ)言介紹范式,旨在便于理解和記憶,這樣做可能會(huì )出現一些不精確的表述。但對于初學(xué)者應該是個(gè)不錯的入門(mén)。我寫(xiě)下這些的目的主要是為了加強 記憶,其實(shí)我也比較菜,我希望當我對一些概念生疏的時(shí)候,回過(guò)頭來(lái)看看自己寫(xiě)的筆記,可以快速地進(jìn)入狀態(tài)。如果你發(fā)現其中用錯誤,請指正。
下面開(kāi)始進(jìn)入正題:
一、基礎概念
要理解范式,首先必須對知道什么是關(guān)系數據庫,如果你不知道,我可以簡(jiǎn)單的不能再簡(jiǎn)單的說(shuō)一下:關(guān)系數據庫就是用二維表來(lái)保存數據。表和表之間可以……(省略10W字)。
然后你應該理解以下概念:
實(shí)體:現實(shí)世界中客觀(guān)存在并可以被區別的事物。比如“一個(gè)學(xué)生”、“一本書(shū)”、“一門(mén)課”等等。值得強調的是這里所說(shuō)的“事物”不僅僅是看得見(jiàn)摸得著(zhù)的“東西”,它也可以是虛擬的,不如說(shuō)“老師與學(xué)校的關(guān)系”。
屬性:教科書(shū)上解釋為:“實(shí)體所具有的某一特性”,由此可見(jiàn),屬性一開(kāi)始是個(gè)邏輯概念,比如說(shuō),“性別”是“人”的一個(gè)屬性。在關(guān)系數據庫中,屬性又是個(gè)物理概念,屬性可以看作是“表的一列”。
元組:表中的一行就是一個(gè)元組。
分量:元組的某個(gè)屬性值。在一個(gè)關(guān)系數據庫中,它是一個(gè)操作原子,即關(guān)系數據庫在做任何操作的時(shí)候,屬性是“不可分的”。否則就不是關(guān)系數據庫了。
碼:表中可以唯一確定一個(gè)元組的某個(gè)屬性(或者屬性組),如果這樣的碼有不止一個(gè),那么大家都叫候選碼,我們從候選碼中挑一個(gè)出來(lái)做老大,它就叫主碼。
全碼:如果一個(gè)碼包含了所有的屬性,這個(gè)碼就是全碼。
主屬性:一個(gè)屬性只要在任何一個(gè)候選碼中出現過(guò),這個(gè)屬性就是主屬性。
非主屬性:與上面相反,沒(méi)有在任何候選碼中出現過(guò),這個(gè)屬性就是非主屬性。
外碼:一個(gè)屬性(或屬性組),它不是碼,但是它別的表的碼,它就是外碼。
二、6個(gè)范式
好了,上面已經(jīng)介紹了我們掌握范式所需要的全部基礎概念,下面我們就來(lái)講范式。首先要明白,范式的包含關(guān)系。一個(gè)數據庫設計如果符合第二范式,一定也符合第一范式。如果符合第三范式,一定也符合第二范式…
第一范式(1NF):屬性不可分。
在前面我們已經(jīng)介紹了屬性值的概念,我們說(shuō),它是“不可分的”。而第一范式要求屬性也不可分。那么它和屬性值不可分有什么區別呢?給一個(gè)例子:
name
tel
age
大寶
13612345678
22
小明
13988776655
010-1234567
21
Ps:這個(gè)表中,屬性值“分”了。
name
tel
age
手機
座機
大寶
13612345678
021-9876543
22
小明
13988776655
010-1234567
21
Ps:這個(gè)表中,屬性 “分”了。
這兩種情況都不滿(mǎn)足第一范式。不滿(mǎn)足第一范式的數據庫,不是關(guān)系數據庫!所以,我們在任何關(guān)系數據庫管理系統中,做不出這樣的“表”來(lái)。
第二范式(2NF):符合1NF,并且,非主屬性完全依賴(lài)于碼。
聽(tīng)起來(lái)好像很神秘,其實(shí)真的沒(méi)什么。
一 個(gè)候選碼中的主屬性也可能是好幾個(gè)。如果一個(gè)主屬性,它不能單獨做為一個(gè)候選碼,那么它也不能確定任何一個(gè)非主屬性。給一個(gè)反例:我們考慮一個(gè)小學(xué)的教務(wù) 管理系統,學(xué)生上課指定一個(gè)老師,一本教材,一個(gè)教室,一個(gè)時(shí)間,大家都上課去吧,沒(méi)有問(wèn)題。那么數據庫怎么設計?(學(xué)生上課表)
學(xué)生
課程
老師
老師職稱(chēng)
教材
教室
上課時(shí)間
小明
一年級語(yǔ)文(上)
大寶
副教授
《小學(xué)語(yǔ)文1》
101
14:30
一個(gè)學(xué)生上一門(mén)課,一定在特定某個(gè)教室。所以有(學(xué)生,課程)->教室
一個(gè)學(xué)生上一門(mén)課,一定是特定某個(gè)老師教。所以有(學(xué)生,課程)->老師
一個(gè)學(xué)生上一門(mén)課,他老師的職稱(chēng)可以確定。所以有(學(xué)生,課程)->老師職稱(chēng)
一個(gè)學(xué)生上一門(mén)課,一定是特定某個(gè)教材。所以有(學(xué)生,課程)->教材
一個(gè)學(xué)生上一門(mén)課,一定在特定時(shí)間。所以有(學(xué)生,課程)->上課時(shí)間
因此(學(xué)生,課程)是一個(gè)碼。
然而,一個(gè)課程,一定指定了某個(gè)教材,一年級語(yǔ)文肯定用的是《小學(xué)語(yǔ)文1》,那么就有課程->教材。(學(xué)生,課程)是個(gè)碼,課程卻決定了教材,這就叫做不完全依賴(lài),或者說(shuō)部分依賴(lài)。出現這樣的情況,就不滿(mǎn)足第二范式!
有什么不好嗎?你可以想想:
1、 校長(cháng)要新增加一門(mén)課程叫“微積分”,教材是《大學(xué)數學(xué)》,怎么辦?學(xué)生還沒(méi)選課,而學(xué)生又是主屬性,主屬性不能空,課程怎么記錄呢,教材記到哪呢? ……郁悶了吧?(插入異常)
2、 下學(xué)期沒(méi)學(xué)生學(xué)一年級語(yǔ)文(上)了,學(xué)一年級語(yǔ)文(下)去了,那么表中將不存在一年級語(yǔ)文(上),也就沒(méi)了《小學(xué)語(yǔ)文1》。這時(shí)候,校長(cháng)問(wèn):一年級語(yǔ)文(上)用的什么教材???……郁悶了吧?(刪除異常)
3、 校長(cháng)說(shuō):一年級語(yǔ)文(上)換教材,換成《大學(xué)語(yǔ)文》。有10000個(gè)學(xué)生選了這么課,改動(dòng)好大??!改累死了……郁悶了吧?(修改異常)
那應該怎么解決呢?投影分解,將一個(gè)表分解成兩個(gè)或若干個(gè)表
學(xué)生
課程
老師
老師職稱(chēng)
教室
上課時(shí)間
小明
一年級語(yǔ)文(上)
大寶
副教授
101
14:30
學(xué)生上課表新
課程
教材
一年級語(yǔ)文(上)
《小學(xué)語(yǔ)文1》
課程的表
第三范式(3NF):符合2NF,并且,消除傳遞依賴(lài)
上面的“學(xué)生上課表新”符合2NF,可以這樣驗證:兩個(gè)主屬性單獨使用,不用確定其它四個(gè)非主屬性的任何一個(gè)。但是它有傳遞依賴(lài)!
在哪呢?問(wèn)題就出在“老師”和“老師職稱(chēng)”這里。一個(gè)老師一定能確定一個(gè)老師職稱(chēng)。
有什么問(wèn)題嗎?想想:
1、 老師升級了,變教授了,要改數據庫,表中有N條,改了N次……(修改異常)
2、 沒(méi)人選這個(gè)老師的課了,老師的職稱(chēng)也沒(méi)了記錄……(刪除異常)
3、 新來(lái)一個(gè)老師,還沒(méi)分配教什么課,他的職稱(chēng)記到哪?……(插入異常)
那應該怎么解決呢?和上面一樣,投影分解:
學(xué)生
課程
老師
教室
上課時(shí)間
小明
一年級語(yǔ)文(上)
大寶
101
14:30
老師
老師職稱(chēng)
大寶
副教授
BC范式(BCNF):符合3NF,并且,主屬性不依賴(lài)于主屬性
若關(guān)系模式屬于第一范式,且每個(gè)屬性都不傳遞依賴(lài)于鍵碼,則R屬于BC范式。
通常BC范式的條件有多種等價(jià)的表述:每個(gè)非平凡依賴(lài)的左邊必須包含鍵碼;每個(gè)決定因素必須包含鍵碼。
BC范式既檢查非主屬性,又檢查主屬性。當只檢查非主屬性時(shí),就成了第三范式。滿(mǎn)足BC范式的關(guān)系都必然滿(mǎn)足第三范式。
還可以這么說(shuō):若一個(gè)關(guān)系達到了第三范式,并且它只有一個(gè)候選碼,或者它的每個(gè)候選碼都是單屬性,則該關(guān)系自然達到BC范式。
一般,一個(gè)數據庫設計符合3NF或BCNF就可以了。在BC范式以上還有第四范式、第五范式。
第四范式:要求把同一表內的多對多關(guān)系刪除。
第五范式:從最終結構重新建立原始結構。
但在絕大多數應用中不需要設計到這種程度。并且,某些情況下,過(guò)于范式化甚至會(huì )對數據庫的邏輯可讀性和使用效率起到阻礙。數據庫中一定程度的冗余并不一定是壞事情。如果你對第四范式、第五范式感興趣可以看一看專(zhuān)業(yè)教材,從頭學(xué)起,并且忘記我說(shuō)的一切,以免對你產(chǎn)生誤導。
關(guān)系模式的范式
主要有4種范式,1NF,2NF,3NF,BCNF,按從左至右的順序一種比一種要求更嚴格。要符合某一種范式必須也滿(mǎn)足它前邊的所有范式。一般項目的數據庫設計達到3NF就可以了,而且可根據具體情況適當增加冗余,不必教條地遵守所謂規范。
簡(jiǎn)單而言,1NF就是要求一張表里只放相互關(guān)聯(lián)的字段,一個(gè)字段里只放一條信息,這只是最基本的要求。至于2NF,3NF,BCNF雖然描述的內容不同,但表現在數據特點(diǎn)上很相似,就好比在說(shuō)不要為了向某廠(chǎng)訂購一批貨記下來(lái),就把的廠(chǎng)的面積、電話(huà)等都放在同一張表里,而應該用兩張表,以盡量避免浪費數據存儲空間。因為和同一個(gè)廠(chǎng)可能會(huì )交易好幾次,但沒(méi)必要每次交易都記錄全部的信息。
從范式所允許的函數依賴(lài)方面進(jìn)行比較,四種范式之間的關(guān)聯(lián)如下圖所示。
以下對每種范式作一一說(shuō)明。
2.3.4.2 第一范式
在關(guān)系模式R中的每一個(gè)具體關(guān)系r中,如果每個(gè)屬性值 都是不可再分的最小數據單位,則稱(chēng)R是第一范式的關(guān)系。
例:如職工號,姓名,電話(huà)號碼組成一個(gè)表(一個(gè)人可能有一個(gè)辦公室電話(huà) 和一個(gè)家里電話(huà)號碼) 規范成為1NF有三種方法:
一是重復存儲職工號和姓名。這樣,關(guān)鍵字只能是電話(huà)號碼。
二是職工號為關(guān)鍵字,電話(huà)號碼分為單位電話(huà)和住宅電話(huà)兩個(gè)屬性
三是職工號為關(guān)鍵字,但強制每條記錄只能有一個(gè)電話(huà)號碼。
以上三個(gè)方法,第一種方法最不可取,按實(shí)際情況選取后兩種情況。
2.3.4.3 第二范式
關(guān)系的第二范式(2NF)定義: 如果關(guān)系模式R為1NF,并且R中的每一個(gè)非主屬性都完全依賴(lài)于R的某個(gè)候選關(guān)鍵字,則稱(chēng)R是第二范式的,簡(jiǎn)記為2NF。
【例2.40】 設有關(guān)系模式R(學(xué)號S#,課程號C#,成績(jì)G,任課教師TN,教師專(zhuān)長(cháng)TS),基于R的函數依賴(lài)集F={(S#,C#)→G,C#→TN,TN→TS},判斷R是否為2NF。
解:
(1) 容易看出,關(guān)系模式R是1NF。因為R符合關(guān)系的定義,R的所有屬性值都是不可再分的原子值。
R是否為2NF,應根據2NF的定義來(lái)判斷。
首先要確定關(guān)系模式R中各屬性間的函數依賴(lài)情況。如果沒(méi)有直接給出R的函數依賴(lài)集,就要按照語(yǔ)義把它確定下來(lái)。在本例中,已直接給出基于R的函數依賴(lài)集F,我們可使用阿氏推理規則并結合下面介紹的方法,進(jìn)一步確定R中哪些是主屬性、哪些是非主屬性、侯選關(guān)鍵字由哪些屬性構成。
方法① 寫(xiě)出函數依賴(lài)集F中的各個(gè)函數依賴(lài)以幫助分析。方法①的特點(diǎn)是直接。
F={(S#,C#)→G,
C#→TN,
TN→TS
}
方法② 用有向圖表示屬性間函數依賴(lài),結點(diǎn)表示屬性,方框包含若干個(gè)結點(diǎn)表示屬性組合,有向箭頭表示函數依賴(lài)。本例的函數依賴(lài)圖如圖2.9所示。方法②的特點(diǎn)是直觀(guān)。
圖2.9 函數依賴(lài)圖例子
方法③ 把關(guān)系模式R與函數依賴(lài)集F結合起來(lái),屬性組合用下劃線(xiàn)(或上劃線(xiàn))表示,函數依賴(lài)用有向箭頭表示。本例的函數依賴(lài)簡(jiǎn)圖如圖2.10所示。方法③的特點(diǎn)是簡(jiǎn)單。
圖2.10函數依賴(lài)簡(jiǎn)圖例子
用阿氏推理規則由F可推出:(S#,C#)→{S#,C#,G,TN,TS},即屬性組合(S#,C#)是R的候選關(guān)鍵字(R只有這一個(gè)候選鍵)。(S#,C#)的一個(gè)值可惟一標識R中的一個(gè)元組(并且沒(méi)有多余的屬性)。
在R中,S#,C#是主屬性;其余的屬性G,TN,TS為非主屬性。
借助上面的圖,我們可以看到,非主屬性G對鍵是完全依賴(lài):(S#,C#)→G。但非主屬性TN,TS對鍵是部分依賴(lài)(他們僅依賴(lài)于鍵的真子集C#)。由于R中存在非主屬性對候選鍵的部分依賴(lài),所以關(guān)系模式R不是2NF。
R中存在非主屬性對候選鍵的部分依賴(lài),將會(huì )引起數據冗余、數據操作異常等問(wèn)題??梢园殃P(guān)系R無(wú)損聯(lián)接地分解成兩個(gè)2NF的關(guān)系模式:
ρ={R1,R2},R1={S#.C#,G},R2={C#,TN,TS}。
【例2.41】選課關(guān)系 SCI(SNO,CNO,GRADE,CREDIT)其中SNO為學(xué)號, CNO為課程號,GRADEGE 為成績(jì),CREDIT 為學(xué)分。
由以上條件,關(guān)鍵字為組合關(guān)鍵字(SNO,CNO)
在應用中使用以上關(guān)系模式有以下問(wèn)題:
a.數據冗余,假設同一門(mén)課由40個(gè)學(xué)生選修,學(xué)分就 重復40次。
b.更新異常,若調整了某課程的學(xué)分,相應的元組CREDIT值都要更新,有可能會(huì )出現同一門(mén)課學(xué)分不同。
c.插入異常,如計劃開(kāi)新課,由于沒(méi)人選修,沒(méi)有學(xué)號關(guān)鍵字,只能等有人選修才能把課程和學(xué)分存入。
d.刪除異常,若學(xué)生已經(jīng)結業(yè),從當前數據庫刪除選修記錄,就會(huì )可能連課程號及學(xué)分完全從數據庫中刪除,則此門(mén)課程及學(xué)分記錄無(wú)法保存。
原因:非關(guān)鍵字屬性CREDIT僅函數依賴(lài)于CNO,也就是CREDIT部分依賴(lài)組合關(guān)鍵字(SNO,CNO)而不是完全依賴(lài)。
解決方法:分成兩個(gè)關(guān)系模式 SC1(SNO,CNO,GRADE),C2(CNO,CREDIT)。新關(guān)系包括兩個(gè)關(guān)系模式,它們之間通過(guò)SC1中的外關(guān)鍵字CNO相聯(lián)系,需要時(shí)再進(jìn)行自然聯(lián)接,恢復了原來(lái)的關(guān)系
2.3.4.4 第三范式
關(guān)系的第三范式(3NF)定義: 如果關(guān)系模式R為2NF,并且R中的每一個(gè)非主屬性都不傳遞依賴(lài)于R的某個(gè)候選關(guān)鍵字,則稱(chēng)R是第三范式的,簡(jiǎn)記為3NF。
【例2.42】續上例2.40(R(學(xué)號S#,課程號C#,成績(jì)G,任課教師TN,教師專(zhuān)長(cháng)TS)),判斷關(guān)系模式R1={S#.C#,G},R2={C#,TN,TS} 是否為3NF。
解:
(1) 在關(guān)系模式R1={S#,C#,G},候選關(guān)鍵字是(S#,C#),主屬性是S#,C#,非主屬性是G,函數依賴(lài)為(S#,C#)→G。 由于R1中不存在非主屬性對候選關(guān)鍵字的傳遞依賴(lài),所以關(guān)系模式R1是3NF。
(2) 在關(guān)系模式R2={C#,TN,TS},候選關(guān)鍵字是C#,主屬性是C#,非主屬性是TN,TS,函數依賴(lài)為C#→TN,TN→TS。由于R2中存在非主屬性對候選關(guān)鍵字的傳遞依賴(lài)C# TS,所以關(guān)系模式R2不是3NF。
可以把關(guān)系R2無(wú)損聯(lián)接地分解成兩個(gè)3NF的關(guān)系模式:
ρ={R3,R4},R3={C#,TN},R4={TN,TS}。
【例2.43】如(SNO,SNAME,DNO,DNAME,LOCATION) 各屬性分別代表學(xué)號,
姓名,所在系,系名稱(chēng),系地址。 判斷關(guān)系模式S1是否為3NF。
關(guān)鍵字SNO決定各個(gè)屬性。由于是單個(gè)關(guān)鍵字,沒(méi)有部分依賴(lài)的問(wèn)題,是2NF。
但這關(guān)系有大量的冗余,有關(guān)學(xué)生所在的幾個(gè)屬性DNO,DNAME,LOCATION將重復存儲,插入,刪除和修改時(shí)也將產(chǎn)生類(lèi)似以上例的情況。
原因:關(guān)系中存在傳遞依賴(lài)造成的。關(guān)鍵字 SNO 對 LOCATION 函數決定是通過(guò)傳遞依賴(lài):SNO -> DNO,及DNO -> LOCATION實(shí)現的。也就是說(shuō),SNO不直接決定非主屬性L(fǎng)OCATION,不是3NF。
解決目地:每個(gè)關(guān)系模式中不能留有傳遞依賴(lài)。
解決方法:分為兩個(gè)關(guān)系 S(SNO,SNAME,DNO),D(DNO,DNAME,LOCATION)
注意:關(guān)系S中不能沒(méi)有外關(guān)鍵字DNO。否則兩個(gè)關(guān)系之間失去聯(lián)系。
2.3.4.5 Boyce-Codd范式
關(guān)系的Boyce-Codd范式(BCNF)定義: 如果關(guān)系模式R為1NF,并且R中的每一個(gè)函數依賴(lài)X→Y(YÏX),必有X是R的超關(guān)鍵字,則稱(chēng)R是Boyce-Codd范式的,簡(jiǎn)記為BCNF。
從BCNF的定義中,可以明顯地得出如下結論:
(1) 所有非主屬性對鍵是完全函數依賴(lài);
(2) 所有主屬性對不包含它的鍵是完全函數依賴(lài);
(3)沒(méi)有屬性完全函數依賴(lài)于非鍵的任何屬性組合。
與2NF,3NF的定義不同,BCNF的定義直接建立在1NF的基礎上。但實(shí)質(zhì)上BCNF是3NF的改進(jìn)形式。3NF僅考慮了非主屬性對鍵的依賴(lài)情況,BCNF把主屬性對鍵的依賴(lài)情況也包括進(jìn)去。BCNF要求滿(mǎn)足的條件比3NF所要求的更高。如果關(guān)系模式R是BCNF的,那么R必定是3NF,反之,則不一定成立。
【例2.43】 續前例2.42(學(xué)號S#,課程號C#,成績(jì)G,任課教師TN,教師專(zhuān)長(cháng)TS),判斷兩個(gè)3NF關(guān)系模式R3={C#,TN},R4={TN,TS}是否為BCNF。
解:在關(guān)系模式R3中有函數依賴(lài)C#→TN,決定因素C#是R3的鍵;
在關(guān)系模式R4中有函數依賴(lài)TN→TS,決定因素TN是R4的鍵;
R3,R4都滿(mǎn)足BCNF的定義,所以,這兩個(gè)關(guān)系模式都是BCNF。
【例2.44】配件管理關(guān)系模式 WPE(WNO,PNO,ENO,QNT)分別表倉庫號,配件號,職工號,數量。有以下條件
a.一個(gè)倉庫有多個(gè)職工。
b.一個(gè)職工僅在一個(gè)倉庫工作。
c.每個(gè)倉庫里一種型號的配件由專(zhuān)人負責,但一個(gè)人可以管理幾種配件。
d.同一種型號的配件可以分放在幾個(gè)倉庫中。
分析:由以上得 PNO 不能確定QNT,由組合屬性(WNO,PNO)來(lái)決定,存在函數依賴(lài)(WNO,PNO) -> ENO。由于每個(gè)倉庫里的一種配件由專(zhuān)人負責,而一個(gè)人可以管理幾種配件,所以有組合屬性(WNO,PNO)才能確定負責人,有(WNO,PNO)-> ENO。因為 一個(gè)職工僅在一個(gè)倉庫工作,有ENO -> WNO。由于每個(gè)倉庫里的一種配件由專(zhuān)人負責,而一個(gè)職工僅在一個(gè)倉庫工作,有 (ENO,PNO)-> QNT。
找一下候選關(guān)鍵字,因為(WNO,PNO) -> QNT,(WNO,PNO)-> ENO ,因此 (WNO,PNO)可以決定整個(gè)元組,是一個(gè)候選關(guān)鍵字。根據ENO->WNO,(ENO,PNO)->QNT,故(ENO,PNO)也能決定整個(gè)元組,為另一個(gè)候選關(guān)鍵字。屬性ENO,WNO,PNO 均為主屬性,只有一個(gè)非主屬性QNT。它對任何一個(gè)候選關(guān)鍵字都是完全函數依賴(lài)的,并且是直接依賴(lài),所以該關(guān)系模式是3NF。
分析一下主屬性。因為ENO->WNO,主屬性ENO是WNO的決定因素,但是它本身不是關(guān)鍵字,只是組合關(guān)鍵字的一部分。這就造成主屬性WNO對另外一個(gè)候選關(guān)鍵字(ENO,PNO)的部 分依賴(lài),因為(ENO,PNO)-> ENO但反過(guò)來(lái)不成立,而P->WNO,故(ENO,PNO)-> WNO 也是傳遞依賴(lài)。
雖然沒(méi)有非主屬性對候選關(guān)鍵遼的傳遞依賴(lài),但存在主屬性對候選關(guān)鍵字的傳遞依賴(lài),同樣也會(huì )帶來(lái)麻煩。如一個(gè)新職工分配到倉庫工作,但暫時(shí)處于實(shí)習階段,沒(méi)有獨立負責對某些配件的管理任務(wù)。由于缺少關(guān)鍵字的一部分PNO而無(wú)法插入到該關(guān)系中去。又如某個(gè)人改成不管配件了去負責安全,則在刪除配件的同時(shí)該職工也會(huì )被刪除。
解決辦法:分成管理EP(ENO,PNO,QNT),關(guān)鍵字是(ENO,PNO)工作EW(ENO,WNO)其關(guān)鍵字是ENO
缺點(diǎn):分解后函數依賴(lài)的保持性較差。如此例中,由于分解,函數依賴(lài)(WNO,PNO)-> ENO 丟失了, 因而對原來(lái)的語(yǔ)義有所破壞。沒(méi)有體現出每個(gè)倉庫里一種部件由專(zhuān)人負責。有可能出現 一部件由兩個(gè)人或兩個(gè)以上的人來(lái)同時(shí)管理。因此,分解之后的關(guān)系模式降低了部分完整性約束。