第二正規化的核心在於:所有非主鍵欄位都必須完全依賴於主鍵。也就是說,資料表中的每個非主鍵欄位都應該直接且唯一地由主鍵決定,不能僅依賴主鍵的一部分(針對複合主鍵而言),也不能依賴其他非主鍵欄位。
在第一正規化(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 為外鍵 |
更新後的資料表關聯圖如下: