第一范式(1NF):確保表中的每個字段都是不可分割的基本數據項。
第二范式(2NF):在滿足1NF的基礎上,確保非主屬性完全依賴于主鍵。
第三范式(3NF):在滿足2NF的基礎上,確保非主屬性不傳遞依賴于主鍵。
使用 StudentCourse
表作為基礎,來解釋第一范式(1NF)。
第一范式 (1NF) 的核心要求:
確保表中的每一個單元格(字段值)都包含單一、不可再分割的基本數據項。換句話說,表中的每一列都必須是原子性的,不能包含多個值或復合值。
回顧之前的 StudentCourse
表:
StudentID (學號) | StudentName (姓名) | StudentDepartment (系別) | CourseID (課程號) | CourseName (課程名) | Professor (教授) |
---|---|---|---|---|---|
1001 | 張三 | 計算機系 | CS101 | 數據結構 | 李教授 |
1001 | 張三 | 計算機系 | CS201 | 數據庫原理 | 王教授 |
1002 | 李四 | 電子系 | EE101 | 電路基礎 | 趙教授 |
1003 | 王五 | 計算機系 | CS101 | 數據結構 | 李教授 |
1003 | 王五 | 計算機系 | CS301 | 操作系統 | 劉教授 |
分析 StudentCourse
表是否滿足 1NF:
現在我們來逐一檢查這個表中的每一列,看看它們是否都滿足原子性(不可分割)的要求:
- StudentID (學號): 例如 “1001”。這是一個單一的數值,不能再分割成更小的有意義的部分(比如不能把它分成 ‘1’, ‘0’, ‘0’, ‘1’ 并認為每個都有獨立意義)。滿足 1NF。
- StudentName (姓名): 例如 “張三”。雖然姓名可以拆分成姓氏和名字(“張” 和 “三”),但在數據庫設計中,通常將整個姓名視為一個不可分割的字符串來處理,特別是當我們不需要單獨查詢姓氏或名字時。如果業務上需要單獨處理姓氏和名字,才需要拆分成兩列。通常認為滿足 1NF。
- StudentDepartment (系別): 例如 “計算機系”。這是一個單一的文本值,表示一個系別。滿足 1NF。
- CourseID (課程號): 例如 “CS101”。這是一個單一的標識符,不能再分割。滿足 1NF。
- CourseName (課程名): 例如 “數據結構”。這是一個單一的文本值。滿足 1NF。
- Professor (教授): 例如 “李教授”。這是一個單一的文本值。滿足 1NF。
結論: 在這個例子中,StudentCourse
表的每一列都只包含單一、不可分割的數據項。因此,這個表滿足第一范式 (1NF)。
一個不滿足 1NF 的例子:
假設我們有一個StudentInfo
表,其中存儲了學生的聯系電話,但允許一個學生有多個電話:
StudentID | StudentName | PhoneNumbers |
---|---|---|
1001 | 張三 | 13812345678, 13987654321 |
1002 | 李四 | 13700001111 |
1003 | 王五 | 13611112222, 13833334444, 13955556666 |
在這個表中,PhoneNumbers
列包含了多個電話號碼,用逗號分隔。這違反了 1NF,因為該列的單元格包含了多個基本數據項(多個電話號碼)。
要使其滿足 1NF,我們需要將每個電話號碼放在單獨的一行,或者創建一個單獨的 StudentPhone
表。
希望這個例子能幫助你理解第一范式的要求!
好的,我們來通過具體的例子來解釋“完全依賴”和“不傳遞依賴”這兩個概念,它們是第二范式(2NF)和第三范式(3NF)的核心。
假設我們有一個存儲學生選修課程信息的表:
表:StudentCourse (學生選課表)
StudentID (學號) | StudentName (姓名) | StudentDepartment (系別) | CourseID (課程號) | CourseName (課程名) | Professor (教授) |
---|---|---|---|---|---|
1001 | 張三 | 計算機系 | CS101 | 數據結構 | 李教授 |
1001 | 張三 | 計算機系 | CS201 | 數據庫原理 | 王教授 |
1002 | 李四 | 電子系 | EE101 | 電路基礎 | 趙教授 |
1003 | 王五 | 計算機系 | CS101 | 數據結構 | 李教授 |
1003 | 王五 | 計算機系 | CS301 | 操作系統 | 劉教授 |
這個表的主鍵是 (StudentID, CourseID)
,因為一個學生可以選多門課,一門課可以被多個學生選,只有同時知道學號和課程號才能唯一確定一行記錄。
2. 第二范式 (2NF) - 完全依賴 (Full Dependency)
定義: 在滿足第一范式(1NF)的基礎上,非主屬性必須完全依賴于整個主鍵,而不僅僅是主鍵的一部分。
問題: 如果主鍵是由多個屬性組成的(復合主鍵),我們需要檢查每個非主屬性是否依賴于所有主鍵屬性。
在 StudentCourse 表中:
- 主鍵: (StudentID, CourseID)
- 非主屬性: StudentName, StudentDepartment, CourseName, Professor
現在我們檢查每個非主屬性是否完全依賴于(StudentID, CourseID)
:
- StudentName (姓名): 姓名是由學號
StudentID
決定的,和選了哪門課CourseID
無關。所以StudentName
只依賴于StudentID
,而不是(StudentID, CourseID)
。這叫部分依賴 (Partial Dependency)。 - StudentDepartment (系別): 系別也是由學號
StudentID
決定的,和課程號CourseID
無關。所以StudentDepartment
只依賴于StudentID
,而不是(StudentID, CourseID)
。這也是部分依賴。 - CourseName (課程名): 課程名是由課程號
CourseID
決定的,和學生的學號StudentID
無關。所以CourseName
只依賴于CourseID
,而不是(StudentID, CourseID)
。這同樣是部分依賴。 - Professor (教授): 教授通常是由課程號
CourseID
決定的(假設一門課只有一個固定教授),和學生的學號StudentID
無關。所以Professor
只依賴于CourseID
,而不是(StudentID, CourseID)
。這也是部分依賴。
結論: StudentCourse 表不滿足 2NF,因為存在非主屬性(StudentName, StudentDepartment, CourseName, Professor)部分依賴于主鍵(StudentID, CourseID)
的子集(要么只依賴StudentID
,要么只依賴CourseID
)。
如何修正 (分解): 我們需要將表分解,使得每個表的非主屬性都完全依賴于該表的主鍵。
- Student (學生表): 主鍵
StudentID
StudentID (學號) StudentName (姓名) StudentDepartment (系別) 1001 張三 計算機系 1002 李四 電子系 1003 王五 計算機系 - Course (課程表): 主鍵
CourseID
CourseID (課程號) CourseName (課程名) Professor (教授) CS101 數據結構 李教授 CS201 數據庫原理 王教授 EE101 電路基礎 趙教授 CS301 操作系統 劉教授 - StudentSC (學生選課關系表): 主鍵
(StudentID, CourseID)
StudentID (學號) CourseID (課程號) 1001 CS101 1001 CS201 1002 EE101 1003 CS101 1003 CS301
現在檢查這些新表:
- Student 表的主鍵是
StudentID
,所有非主屬性 (StudentName, StudentDepartment) 都完全依賴于StudentID
。 - Course 表的主鍵是
CourseID
,所有非主屬性 (CourseName, Professor) 都完全依賴于CourseID
。 - StudentSC 表的主鍵是
(StudentID, CourseID)
,它沒有其他非主屬性,所以自然滿足。
這些分解后的表都滿足了 2NF。
3. 第三范式 (3NF) - 不傳遞依賴 (No Transitive Dependency)
定義: 在滿足第二范式(2NF)的基礎上,非主屬性必須不傳遞依賴于主鍵。也就是說,非主屬性不能依賴于另一個非主屬性。
問題: 我們需要檢查是否存在“主鍵 -> 非主屬性 A -> 非主屬性 B”這樣的依賴鏈條,其中 B 就是傳遞依賴于主鍵。
在修正后的 Student 表中:
- 主鍵:
StudentID
- 非主屬性: StudentName, StudentDepartment
檢查是否存在傳遞依賴: StudentID
->StudentDepartment
(學號決定系別)StudentDepartment
-> ? 這個系別 (StudentDepartment
) 是否又決定了其他的非主屬性?在我們的 Student 表中,系別只決定了它自己,沒有決定其他非主屬性 (StudentName)。所以沒有傳遞依賴。
在修正后的 Course 表中:- 主鍵:
CourseID
- 非主屬性: CourseName, Professor
檢查是否存在傳遞依賴: CourseID
->Professor
(課程號決定教授)Professor
-> ? 這個教授 (Professor
) 是否又決定了其他的非主屬性?在我們的 Course 表中,教授只決定了它自己,沒有決定其他非主屬性 (CourseName)。所以沒有傳遞依賴。
假設我們有一個不滿足 3NF 的表:
表:StudentDept (學生系別表 - 假設大學有系主任)
StudentID (學號) | StudentName (姓名) | StudentDepartment (系別) | DepartmentHead (系主任) |
---|---|---|---|
1001 | 張三 | 計算機系 | 陳主任 |
1002 | 李四 | 電子系 | 吳主任 |
1003 | 王五 | 計算機系 | 陳主任 |
- 主鍵:
StudentID
(假設學號唯一) - 非主屬性: StudentName, StudentDepartment, DepartmentHead
檢查依賴關系:
StudentID
->StudentName
(滿足)StudentID
->StudentDepartment
(滿足)StudentID
->DepartmentHead
? 不完全是。學號本身不直接決定系主任。但是,我們可以通過學號找到系別 (StudentID
->StudentDepartment
),然后通過系別找到系主任 (StudentDepartment
->DepartmentHead
)。所以,DepartmentHead
是傳遞依賴于主鍵StudentID
的。StudentID
->StudentDepartment
->DepartmentHead
。
結論: StudentDept 表不滿足 3NF,因為存在非主屬性DepartmentHead
傳遞依賴于主鍵StudentID
。
如何修正 (分解): 我們需要將傳遞依賴的非主屬性分離出來。
- Student (學生表): 主鍵
StudentID
-
StudentID (學號) StudentName (姓名) StudentDepartment (系別) 1001 張三 計算機系 1002 李四 電子系 1003 王五 計算機系 - Department (系別表): 主鍵
StudentDepartment
(可以用系別名稱或系編號作為主鍵,這里簡化用名稱)StudentDepartment (系別) DepartmentHead (系主任) 計算機系 陳主任 電子系 吳主任
現在檢查這些新表:
- Student 表滿足 3NF。
- Department 表的主鍵是
StudentDepartment
,唯一的非主屬性DepartmentHead
完全依賴于它,并且沒有其他非主屬性可以依賴,所以也滿足 3NF。
總結:
- 完全依賴 (2NF): 非主屬性不能只依賴于復合主鍵的“一部分”。它們必須依賴于整個主鍵。
- 不傳遞依賴 (3NF): 非主屬性不能依賴于另一個非主屬性。它們必須直接依賴于主鍵,不能通過中間的非主屬性間接依賴。
通過滿足這些范式,可以減少數據冗余,避免數據更新異常(插入、刪除、修改異常)。