第二正規化的核心在於:所有非主鍵欄位都必須完全依賴於主鍵。也就是說,資料表中的每個非主鍵欄位都應該直接且唯一地由主鍵決定,不能僅依賴主鍵的一部分(針對複合主鍵而言),也不能依賴其他非主鍵欄位。
在第一正規化(1NF)實務案例文章時我們所設計的學生與課程資料表關聯如下圖:
接下來將以第二正規化的基本原則來優化這兩張資料表
| 欄位名稱 | 說明 | 
|---|---|
| student_id | 主鍵,識別唯一學生 | 
| first_name | 依賴 student_id | 
| last_name | 依賴 student_id | 
| birth_date | 依賴 student_id | 
| address fields | 依賴 student_id | 
結論: 所有欄位都依賴 student_id,符合 2NF。
| 欄位名稱 | 說明 | 
|---|---|
| subject_id | 主鍵,識別唯一科目 | 
| subject_name | 依賴 subject_id | 
| category | ❌不完全依賴 subject_id,可能出現重複與異常 | 
| student_id | 外鍵 | 
結論: category 欄位可能重複出現在不同科目中,若 category 名稱變更,會產生更新異常(update anomaly),需同步修改所有出現的紀錄,且容易遺漏。
建立新的 categories 資料表如下:
| 欄位名稱 | 說明 | 
|---|---|
| category_id | 主鍵 | 
| category_name | 類別名稱(文字) | 
接著,將 subjects 資料表中的 category 欄位,改為外鍵 category_id,對應 categories 資料表的主鍵,形成一對多關聯:
category_id
| 關聯類型 | 解釋 | 
|---|---|
| categories → subjects | categories 表中的一筆資料可以對應到 subjects 表中的多筆資料(一對多) | 
| subjects → categories | subjects 表中以 category_id 為外鍵指向 categories | 
問題:一個學生可以選修多門科目,一門科目也可以有多位學生修習。
結論:這是典型的多對多(Many-to-Many)關係,資料庫設計中不應直接存在此種關係,需透過「中介資料表(joining table)」解決。
| 欄位名稱 | 說明 | 
|---|---|
| student_id | 外鍵,對應 students 表 | 
| subject_id | 外鍵,對應 subjects 表 | 
此表每新增一筆紀錄,表示一位學生選修了一門課程。將原本在 subjects 表中多餘的 student_id 欄位移除,透過 students_subjects 表來維護學生與科目的關係。
這邊主鍵使用聯合類型,即 (student_id, subject_id) 看成一組,來達成唯一識別每一筆資料
| 表格 | 關聯說明 | 
|---|---|
| categories - subjects | 一對多,透過 category_id 連接 | 
| students - students_subjects | 一對多,student_id 為外鍵 | 
| subjects - students_subjects | 一對多,subject_id 為外鍵 | 
更新後的資料表關聯圖如下: