# 資料庫正規化(Database normalization) --- ## 目的 其目的是為了降低資料的「重覆性」與避免「更新異常」的情況發生。 --- ### 範例訂單 | 購買日期 | 客戶ID | 客戶名稱 | 商品名稱 | 單價 | 量(斤) | | -------- | -------- | --------| -------- | -------- | -------- | | 12/24 | p001 | Ken | 香蕉 | 10 | 5 | | 12/24 | p002 |Howard | 蘋果,香蕉,橘子 | 30,10,20 | 2,4,1 | | 12/25 | p003 |Chris | 蘋果 | 30 | 2 | | 12/25 | p003 |Chris | 蘋果 | 30 | 2 | | 12/25 | p004 |May | 蘋果,橘子 | 30,20 | 1,1 | ---- 1NF(First normal form) - 一格(每一列每一欄)只能有一筆資料 - 每筆資料都有一個唯一的主鍵作為識別 2NF (Second normal form) - 符合1NF - 消除部分相依 3NF (Third normal form) - 符合1NF及2NF - 消除遞移相依 ## 1NF - 避免欄位長度無法確定 - 避免出現完全一樣的兩筆資料 ---- 首先將欄位中有多重資料的訂單拆開,然後給每一筆訂單一個唯一鍵 | 購買日期 | 客戶ID | 客戶名稱 | 商品名稱 | 單價 | 量(斤) | | -------- | -------- | --------| -------- | -------- | -------- | | 12/24 | p002 |Howard | 蘋果,香蕉,橘子 | 30,10,20 | 2,4,1 | | 購買日期 | 客戶ID | 客戶名稱 | 商品名稱 | 單價 | 量(斤) | | -------- | -------- | --------| -------- | -------- | -------- | | 12/24 | p002 |Howard | 蘋果 | 30 | 2 | | 12/24 | p002 |Howard | 香蕉 | 10 | 4 | | 12/24 | p002 |Howard | 橘子 | 20 | 1 | ---- 下表是我第一次正規化的結果 |編號| 購買日期 | 客戶ID | 客戶名稱 | 商品名稱 | 單價 | 量(斤) | | --------| -------- | -------- | -------- | -------- | -------- | -------- | |1| 12/24 | p001 | Ken | 香蕉 | 10 | 5 | |2| 12/24 | p002 | Howard | 蘋果 | 30 | 2 | |3| 12/24 | p002 | Howard | 香蕉 | 10 | 4 | |4| 12/24 | p002 | Howard | 橘子 | 20 | 1 | |5| 12/25 | p003 | Chris | 蘋果 | 30 | 2 | |6| 12/25 | p003 | Chris | 蘋果 | 30 | 2 | |7| 12/25 | p004 | May | 蘋果 | 30 | 1| |8| 12/25 | p004 | May | 橘子 | 20 | 1| 失去原本的資料的真實性了,看不出來其實002~004其實是同一筆訂單了,其他多筆資料的訂單也是,所以再弄成下面這樣 ---- ### 訂單 |編號|訂單編號| 購買日期 | 客戶ID | 客戶名稱 | 商品名稱 | 單價 | 量(斤) | | --------| --------| -------- | -------- | -------- | -------- | -------- | -------- | |1|d001| 12/24 | p001 | Ken | 香蕉 | 10 | 5 | |2|d002| 12/24 | p002 | Howard | 蘋果 | 30 | 2 | |3|d002| 12/24 | p002 | Howard | 香蕉 | 10 | 4 | |4|d002| 12/24 | p002 | Howard | 橘子 | 20 | 1 | |5|d003| 12/25 | p003 | Chris | 蘋果 | 30 | 2 | |6|d004| 12/25 | p003 | Chris | 蘋果 | 30 | 2 | |7|d005| 12/25 | p004 | May | 蘋果 | 30 | 1| |8|d005| 12/25 | p004 | May | 橘子 | 20 | 1| 感覺資料變更多了啊!!! --- ## 2NF 消除部分相依 - 將商品名稱與單價獨立出來 ---- ### 訂單 |編號|訂單編號| 購買日期 | 客戶ID |客戶名稱 | 商品名稱 | 量(斤)| | --------| -------- | -------- | -------- | -------- | -------- | -------- | |1|d001| 12/24 | p001 |Ken | 香蕉 | 5 | |2|d002| 12/24 | p002 |Howard | 蘋果 | 2 | |3|d002| 12/24 | p002 |Howard | 香蕉 | 4 | |4|d002| 12/24 | p002 |Howard | 橘子 | 1 | |5|d003| 12/25 | p003 |Chris | 蘋果 | 2 | |6|d004| 12/25 | p003 |Chris | 蘋果 | 2 | |7|d005| 12/25 | p004 |May | 蘋果 | 1| |8|d005| 12/25 | p004 |May | 橘子 | 1| ### 商品資訊 |商品名稱|單價| | -------- | -------- | | 香蕉 | 10 | | 蘋果 | 30 | | 橘子 | 20 | --- ## 3NF 消除遞移相依 - 何謂遞移相依? X->Y,Y->Z 所以X->Z - 將客戶ID與客戶名稱獨立出來 ---- ### 訂單 |編號|訂單編號| 購買日期 | 客戶ID | 商品名稱 | 量(斤)| | --------| -------- | -------- | -------- | -------- | -------- | |1|d001| 12/24 | p001 | 香蕉 | 5 | |2|d002| 12/24 | p002 | 蘋果 | 2 | |3|d002| 12/24 | p002 | 香蕉 | 4 | |4|d002| 12/24 | p002 | 橘子 | 1 | |5|d003| 12/25 | p003 | 蘋果 | 2 | |6|d004| 12/25 | p003 | 蘋果 | 2 | |7|d005| 12/25 | p004 | 蘋果 | 1 | |8|d005| 12/25 | p004 | 橘子 | 1 | ### 客戶資料 | 客戶ID | 客戶名稱 | | -------- | -------- | | p001 | Ken | | p002 | Howard | | p003 | Chris | | p004 | May | ### 商品資訊 |商品名稱|單價| | -------- | -------- | | 香蕉 | 10 | | 蘋果 | 30 | | 橘子 | 20 | ---- ### 正規化練習 ![正規化練習](https://i.imgur.com/r4U4xaU.png) * Timesheet(考勤單)要多 所以要取得Invoice(發票)ID,必須把 Invoice的Timesheetid刪掉 * Employee Address1 Address2 違反第一正規化 * Employee ZIP 違反正規化 * 地址在資料庫寫法必須分開為城市 路 巷等等才不違反規定 * Vehicle的EmplyeeID應該與VehicleID形成一個新表 * EmployeeType與Employee應該是1->多 * Salary不屬於Employee * 因為Timesheet中有ClientID所以Client對TimeSheet應該要有一條 1->多 修改版 ![正規化練習](https://i.imgur.com/87GhRp3.png) --- ## 參考資料 - [Normalization - 1NF, 2NF, 3NF and 4NF ](https://www.youtube.com/watch?v=UrYLYV7WSHM) - [為何使用資料庫儲存資料時,需要先執行正規化? ](https://www.ithome.com.tw/node/47440)