資料庫正規化(Database normalization),又稱資料庫或資料庫的正規化、標準化,簡體中文翻譯為「数据库规范化」,是資料庫設計中的一系列原理和技術,以減少資料庫中資料冗餘,增進資料的一致性。
正規化即是作資料表的優化,但資料表的優化沒有標準答案,甚至在不同環境下會有不同的評價。
正規化是在資料庫中組織資料的程序。其中包括建立資料表,以及在這些資料表之間根據規則建立關聯性,這些規則的設計目的是:透過刪除重複性和不一致的相依性,保護資料並讓資料庫更有彈性。
重複的資料會浪費磁碟空間,並產生維護方面的問題。如果必須變更現有資料,並且該資料的位置超過一個以上,就必須在所有位置上以完全相同的方式進行變更。如果資料只儲存於 [客戶] 資料表中,而不儲存於資料庫中任何其他位置,變更客戶地址就會更容易執行。
第1正規形式 (first normal form,1NF)
定義:一個關聯表為第一正規化表格,若且唯若關聯表中的每一個屬性其值皆為基元值 (Atomic Value)。
非正規形資料的欄位值無法再分離出來時,稱做第1正規形。非正規形資料因同一欄位存在複數值,會發生無法進行演算的問題。例如1筆訂單資料存在多項商品的明細,將其分離出成1筆1筆 的單筆明細,就成為第1正規形式。
以下也是不符合第1正規形式
應該修改為以下:
第2正規形式 (second normal form,2NF)
定義:一個關聯表為第二正規化表格,若且唯若關聯表中,所有非鍵值屬性皆完全功能相依於主鍵。
符合第1正規形而且「非Key值完全從屬於候補Key值」,稱做第2正規形。如下範例,訂單資料內存在非Key值「商品名稱」,部分從屬於候補Key值的「商品代碼」({訂單號碼,商品代號}→商品名稱),因此將其分離出來,即成為第2正規形式。
第2正規形式就是要去除部分相依,部分相依是指~主鍵X (X為屬性子集合) 由多個屬性組成,某非鍵值屬性依賴主鍵之部分時,則稱該屬性“部份相依”於主鍵。
當主鍵為{訂單號碼,商品代號},商品名稱相依於{商品代號},所以存在部份相依。
第3正規形式 (third normal form,3NF)
定義:一個關聯表為第三正規化表格,若且唯若該關聯表中,不存在非鍵值屬性遞移相依於主鍵。
符合第2正規形而且不含有「非Key值推移從屬於候補Key值」,稱做第3正規形。如下範例,商品主檔內存在非Key值的「商品類別名稱」,直接從屬於非Key值的「商品類別代號」,推移從屬於主Key值的「商品代號」,因此將其分離出成,即成為第3正規形式 。
第3正規形式就是要去除遞移相依,遞移相依是指~若存在一個非鍵值屬性子集合 Z,使得 X→Z 且 Z→Y 的功能相依性均成立,則稱之 Y 遞移相依於 X。
BCNF正規形式 (Boyce/Codd normal form; BCNF)
是在第三正規化的基礎上加上稍微更嚴格約束,每個BCNF關係都滿足第三正規化。BCNF去除了屬性間的不必要的函式依賴。 BCNF與第三正規化的不同之處在於:第三正規化中不允許非主屬性被另一個非主屬性決定,但第三正規化允許主屬性被非主屬性決定;而在BCNF中,任何屬性(包括非主屬性和主屬性)都不能被非主屬性所決定。
任何一個BCNF必然滿足:
~所有非主屬性都完全函式依賴於每個候選鍵
~所有主屬性都完全函式依賴於每個不包含它的候選鍵
~沒有任何屬性完全函式依賴於非候選鍵的任何一組屬性
例如著名的SCT關聯,{學生、科目、講師}的關係資料,具有{學生、科目}→講師(前提學生所修的1個科目不會有多位老 師)以及講師→科目(前提1位講師只負責1個科目)的函數從屬性,符合第3正規形,但是「講師」不是SuperKey,不符合BCNF正規形,因此將其分 解成「學生-講師」、「講師-科目」,即成為BCNF正規形(注意分解後,函數從屬關係會改變,原本不是Key值的「講師」變成Key值)。
不分解的話會有
(1)新講師上任,負責科目已確定,還沒有學生時,會發生無法登錄的情形。
(2)學生刪除選課履歷時,講師和科目的資料也會被刪除的情形。
(3)講師變 更科目時,會出現重複的情形。
第4正規形式 (fourth normal form,4NF)
是BC正規化之後的另一層次的規範化。第二正規化、第三正規化、BC正規化關注於屬性集合之間的函式依賴;而第四正規化關注更一般形式稱作多值依賴。也就是符合BCNF,再除去所有的多值相依 (Multi-Valued Dependency)。
多值相依 https://en.wikipedia.org/wiki/Multivalued_dependency
多值相依~關聯表R中有3個欄位以上, R(A,B,C), 主鍵為ABC, 而A對應B時, B有 多個值相對應﹔A對應C時, C有多個值相對應, B和C 無關。
第5正規形式 (fifth normal form,5NF)
以去除多個關係之間的語義相關。一張表滿足第五正規形式若且唯若它的每個連接依賴可由候選鍵推出。也就是符合4NF,且沒有合併相依 (Join Dependency)。
A table T is subject to a join dependency if T can always be recreated by joining multiple tables each having a subset of the attributes of T. 如果表格T可以透過其子集而重建,那麼表格T就是具有合併相依。
合併相依 https://en.wikipedia.org/wiki/Join_dependency
前四階正規化主要是將關聯表每一種相依,分割成「兩」個關聯表來滿足各階的正規化型式,但是,一些非常特殊的關聯表,如果只分割成兩個並不能解決資料重複和異常操作問題。此時,我們需要使用第五階正規化型式,將關聯表分割成三個或以上的關聯表。
例如:每一個科系(department)開多門課;課程(course)可以給多位學生修;學生(student)可以修不同科系的課。三個屬性循環擁有關聯性,而且儲存在同一個關聯表Department_Course_Student,簡稱DCS,如下圖所示:
資料庫正規化練習~
非正規化的檔案
2NF (去除部份相依)
例如以下表單的主鍵是 [學號+課程代號] :
正規化是在資料庫中組織資料的程序。其中包括建立資料表,以及在這些資料表之間根據規則建立關聯性,這些規則的設計目的是:透過刪除重複性和不一致的相依性,保護資料並讓資料庫更有彈性。
重複的資料會浪費磁碟空間,並產生維護方面的問題。如果必須變更現有資料,並且該資料的位置超過一個以上,就必須在所有位置上以完全相同的方式進行變更。如果資料只儲存於 [客戶] 資料表中,而不儲存於資料庫中任何其他位置,變更客戶地址就會更容易執行。
第1正規形式 (first normal form,1NF)
定義:一個關聯表為第一正規化表格,若且唯若關聯表中的每一個屬性其值皆為基元值 (Atomic Value)。
非正規形資料的欄位值無法再分離出來時,稱做第1正規形。非正規形資料因同一欄位存在複數值,會發生無法進行演算的問題。例如1筆訂單資料存在多項商品的明細,將其分離出成1筆1筆 的單筆明細,就成為第1正規形式。
以下也是不符合第1正規形式
應該修改為以下:
第2正規形式 (second normal form,2NF)
定義:一個關聯表為第二正規化表格,若且唯若關聯表中,所有非鍵值屬性皆完全功能相依於主鍵。
符合第1正規形而且「非Key值完全從屬於候補Key值」,稱做第2正規形。如下範例,訂單資料內存在非Key值「商品名稱」,部分從屬於候補Key值的「商品代碼」({訂單號碼,商品代號}→商品名稱),因此將其分離出來,即成為第2正規形式。
第2正規形式就是要去除部分相依,部分相依是指~主鍵X (X為屬性子集合) 由多個屬性組成,某非鍵值屬性依賴主鍵之部分時,則稱該屬性“部份相依”於主鍵。
當主鍵為{訂單號碼,商品代號},商品名稱相依於{商品代號},所以存在部份相依。
第3正規形式 (third normal form,3NF)
定義:一個關聯表為第三正規化表格,若且唯若該關聯表中,不存在非鍵值屬性遞移相依於主鍵。
符合第2正規形而且不含有「非Key值推移從屬於候補Key值」,稱做第3正規形。如下範例,商品主檔內存在非Key值的「商品類別名稱」,直接從屬於非Key值的「商品類別代號」,推移從屬於主Key值的「商品代號」,因此將其分離出成,即成為第3正規形式 。
第3正規形式就是要去除遞移相依,遞移相依是指~若存在一個非鍵值屬性子集合 Z,使得 X→Z 且 Z→Y 的功能相依性均成立,則稱之 Y 遞移相依於 X。
BCNF正規形式 (Boyce/Codd normal form; BCNF)
是在第三正規化的基礎上加上稍微更嚴格約束,每個BCNF關係都滿足第三正規化。BCNF去除了屬性間的不必要的函式依賴。 BCNF與第三正規化的不同之處在於:第三正規化中不允許非主屬性被另一個非主屬性決定,但第三正規化允許主屬性被非主屬性決定;而在BCNF中,任何屬性(包括非主屬性和主屬性)都不能被非主屬性所決定。
任何一個BCNF必然滿足:
~所有非主屬性都完全函式依賴於每個候選鍵
~所有主屬性都完全函式依賴於每個不包含它的候選鍵
~沒有任何屬性完全函式依賴於非候選鍵的任何一組屬性
例如著名的SCT關聯,{學生、科目、講師}的關係資料,具有{學生、科目}→講師(前提學生所修的1個科目不會有多位老 師)以及講師→科目(前提1位講師只負責1個科目)的函數從屬性,符合第3正規形,但是「講師」不是SuperKey,不符合BCNF正規形,因此將其分 解成「學生-講師」、「講師-科目」,即成為BCNF正規形(注意分解後,函數從屬關係會改變,原本不是Key值的「講師」變成Key值)。
不分解的話會有
(1)新講師上任,負責科目已確定,還沒有學生時,會發生無法登錄的情形。
(2)學生刪除選課履歷時,講師和科目的資料也會被刪除的情形。
(3)講師變 更科目時,會出現重複的情形。
第4正規形式 (fourth normal form,4NF)
是BC正規化之後的另一層次的規範化。第二正規化、第三正規化、BC正規化關注於屬性集合之間的函式依賴;而第四正規化關注更一般形式稱作多值依賴。也就是符合BCNF,再除去所有的多值相依 (Multi-Valued Dependency)。
多值相依 https://en.wikipedia.org/wiki/Multivalued_dependency
多值相依~關聯表R中有3個欄位以上, R(A,B,C), 主鍵為ABC, 而A對應B時, B有 多個值相對應﹔A對應C時, C有多個值相對應, B和C 無關。
第5正規形式 (fifth normal form,5NF)
以去除多個關係之間的語義相關。一張表滿足第五正規形式若且唯若它的每個連接依賴可由候選鍵推出。也就是符合4NF,且沒有合併相依 (Join Dependency)。
A table T is subject to a join dependency if T can always be recreated by joining multiple tables each having a subset of the attributes of T. 如果表格T可以透過其子集而重建,那麼表格T就是具有合併相依。
合併相依 https://en.wikipedia.org/wiki/Join_dependency
前四階正規化主要是將關聯表每一種相依,分割成「兩」個關聯表來滿足各階的正規化型式,但是,一些非常特殊的關聯表,如果只分割成兩個並不能解決資料重複和異常操作問題。此時,我們需要使用第五階正規化型式,將關聯表分割成三個或以上的關聯表。
例如:每一個科系(department)開多門課;課程(course)可以給多位學生修;學生(student)可以修不同科系的課。三個屬性循環擁有關聯性,而且儲存在同一個關聯表Department_Course_Student,簡稱DCS,如下圖所示:
資料庫正規化練習~
非正規化的檔案
客戶編號
|
客戶姓名
|
地址
|
運費
|
貨號
|
品名
|
數量
|
日期
|
C001
|
李四
|
台中
|
100.0
|
0201
|
西瓜
|
2,1
|
6/3,6/5
|
C001
|
李四
|
台中
|
100.0
|
0203
|
鳳梨
|
1
|
6/3
|
C003
|
王五
|
台北
|
70.0(
|
0204
|
香蕉
|
2,1
|
6/7,6/8
|
1NF (去除非基元值)
客戶編號
|
客戶姓名
|
地址
|
運費
|
貨號
|
品名
|
數量
|
日期
|
C001
|
李四
|
台中
|
100.0
|
0201
|
西瓜
|
2
|
6/3
|
C001
|
李四
|
台中
|
100.0
|
0201
|
西瓜
|
1
|
6/5
|
C001
|
李四
|
台中
|
100.0
|
0203
|
鳳梨
|
1
|
6/3
|
C003
|
王五
|
台北
|
70.0
|
0204
|
香蕉
|
2
|
6/7
|
C003
|
王五
|
台北
|
70.0
|
0204
|
香蕉
|
1
|
6/8
|
2NF (去除部份相依)
客戶編號
|
客戶姓名
|
地址
|
運費
|
貨號
|
品名
|
客戶編號
|
貨號
|
數量
|
日期
|
||
C001
|
李四
|
台中
|
100.0
|
0201
|
西瓜
|
C001
|
0201
|
2
|
6/3
|
||
C001
|
李四
|
台中
|
100.0
|
0201
|
西瓜
|
C001
|
0201
|
1
|
6/5
|
||
C001
|
李四
|
台中
|
100.0
|
0203
|
鳳梨
|
C001
|
0203
|
1
|
6/3
|
||
C003
|
王五
|
台北
|
70.0
|
0204
|
香蕉
|
C003
|
0204
|
2
|
6/7
|
||
C003
|
王五
|
台北
|
70.0
|
0204
|
香蕉
|
C003
|
0204
|
1
|
6/8
|
3NF (去除遞移相依)
相關參考
http://blog.xuite.net/coke750101/networkprogramming/54648856-%E9%97%9C%E8%81%AF%E6%80%A7%E8%B3%87%E6%96%99%E5%BA%AB%E7%9A%84%E6%AD%A3%E8%A6%8F%E5%8C%96%E5%9F%BA%E7%A4%8E
客戶編號
|
客戶姓名
|
地址
|
運費
|
貨號
|
品名
|
客戶編號
|
貨號
|
數量
|
日期
|
|||
C001
|
李四
|
台中
|
100.0
|
0201
|
西瓜
|
C001
|
0201
|
2
|
6/3
|
|||
C001
|
李四
|
台中
|
100.0
|
0201
|
西瓜
|
C001
|
0201
|
1
|
6/5
|
|||
C001
|
李四
|
台中
|
100.0
|
0203
|
鳳梨
|
C001
|
0203
|
1
|
6/3
|
|||
C003
|
王五
|
台北
|
70.0
|
0204
|
香蕉
|
C003
|
0204
|
2
|
6/7
|
|||
C003
|
王五
|
台北
|
70.0
|
0204
|
香蕉
|
C003
|
0204
|
1
|
6/8
|
相關參考
http://blog.xuite.net/coke750101/networkprogramming/54648856-%E9%97%9C%E8%81%AF%E6%80%A7%E8%B3%87%E6%96%99%E5%BA%AB%E7%9A%84%E6%AD%A3%E8%A6%8F%E5%8C%96%E5%9F%BA%E7%A4%8E
[後記]
上述的資料庫正規化解釋,可能還有些太複雜,以下使用比較白話的方式來解釋。
(1) 1NF (第1正規形式) :
1-1 需要主鍵
1-2 每個欄位只能有一個同性質的值 (例如 電話欄位內不能有兩個電話號碼)
1-3 不能有類似的重複欄位 (例如 address1、address2)
資料表單具有主鍵,最主要的目的有兩個,第一是可以被外部表單關聯,第二是可以確保資料的獨特性(不會重複),其實這兩件事也可以算是一件事。
但是這兩件事有時也未必是同一件事,例如表單有個序號欄位是auto increment並當成主鍵,這樣當然就可以被外部表單關聯,但是如果另外兩個欄位是學號、電話號碼,資料的獨特性就未必能夠確保,因為資料重複也不會有錯誤訊息。
例如 :
序號 | 學號 | 電話 |
1 | 001 | 0900-123-123 |
2 | 001 | 0900-123-123 |
3 | 002 | 0911-111-222 |
序號1跟序號2雖然可以被外部表單關聯,也看似符合獨特性,但是其實學號、電話號碼是重複的。但是,如果主鍵是[學號+電話號碼],這樣就能確保資料不會重複,也可以被外部表單關聯。
因此資料表要成為1NF,需要主鍵是基本條件,但是具有正確的主鍵才是重點。
每個欄位只能有一個同性質的值是為了確保抓出資料的正確性,假如電話欄位內有多個電話號碼,可能是「0900-123-123、0900-111-222」,也可能是「0900-123-123, 0900-111-222」,也可能是「0900-123-123 / 0900-111-222」,也可能只有一個或是多個電話號碼,如此根本無法確認資料不會重複。當然,同性質的意思是,不要出現 0900123123、0900-123-123 這種格式不同的資料。
資料表不能有類似的重複欄位,主要是要確保資料表的彈性,如果存在address1、address2,那麼第三個地址是不是還要再加一個address3欄位? 如果存在這種類似的重複欄位,就必須拉出另外一個資料表,以外鍵與主鍵來關聯。
(2) 2NF (第2正規形式) :
2-1 是1NF
2-2 非鍵值欄位不能部分相依於主鍵
「鍵值欄位」英文是key attributes,指的是具有主鍵特性的欄位,也就是主鍵、候選鍵、次要鍵,「非鍵值欄位」當然就是其他欄位。
學號 | 課程代號 | 教師代號 | 分數 |
001 | A001 | T001 | 80 |
001 | A002 | T002 | 90 |
002 | B001 | T003 | 85 |
以上的[分數]相依於整個主鍵,但是[教師代號]只相依於課程代號,而不是相依於整個主鍵,因此這個表單就不是2NF,因此需要把[教師代號]與[課程代號]拉出來成立另外一個表單。
(3) 3NF (第3正規形式)
3-1 是2NF
3-2 非鍵值欄位不能遞移相依於主鍵
「遞移相依」是指C相依於B,而B相依於主鍵A,則C遞移相依於主鍵A。
課程代號 | 課程名稱 | 教師代號 | 教師姓名 |
A001 | Database MySQL | T001 | John |
A002 | Python Programming Language | T002 | Mary |
A003 | Network Basics | T003 | Tom |
以上表單的[教師姓名]相依於[教師代號],[教師代號]再相依於[課程代號],因此存在「遞移相依」。
因此就必須再拆成以下表單 ~~
課程代號 | 課程名稱 | 教師代號 |
A001 | Database MySQL | T001 |
A002 | Python Programming Language | T002 |
A003 | Network Basics | T003 |
教師表單的主鍵是 [教師代號] :
教師代號 | 教師姓名 |
T001 | John |
T002 | Mary |
T003 | Tom |
其他的正規化陸續再以更多例子來解釋。
0 留言