# 資料庫正規化(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 |
----
### 正規化練習

* Timesheet(考勤單)要多 所以要取得Invoice(發票)ID,必須把 Invoice的Timesheetid刪掉
* Employee Address1 Address2 違反第一正規化
* Employee ZIP 違反正規化
* 地址在資料庫寫法必須分開為城市 路 巷等等才不違反規定
* Vehicle的EmplyeeID應該與VehicleID形成一個新表
* EmployeeType與Employee應該是1->多
* Salary不屬於Employee
* 因為Timesheet中有ClientID所以Client對TimeSheet應該要有一條 1->多
修改版

---
## 參考資料
- [Normalization - 1NF, 2NF, 3NF and 4NF
](https://www.youtube.com/watch?v=UrYLYV7WSHM)
- [為何使用資料庫儲存資料時,需要先執行正規化?
](https://www.ithome.com.tw/node/47440)