資料庫原理學習筆記(二)資料庫正規化
正規化可以理解成在設計資料表時的規範級別,常見的正規化有
- 第一正規化(1NF)
- 第二正規化(2NF)
- 第三正規化(3NF)
- BC正規化(BCNF)
第一正規化
要滿足第一正規化,要求資料表的每個屬性無法再分,也就是需要滿足原子性。可以把“不可再分”理解成無法用一個單獨的值表示,比如說“系”這個屬性,平時常說的“計算機系”,“化學系”實際上指的是系名,而系的管理者被稱為系主任,所以對於“系”這個屬性,只能通過將它拆分成若干屬性的組合(系名,系主任,…)來表示。
所以如果資料表中某個屬性指的是類似上面的“系”這樣的屬性,就不滿足第一正規化,解決辦法就是將這個可以再分的屬性繼續分解
CREATE TABLE student (
id INT NOT NULL AUTO_INCREMENT, /* 學號 */
name VARCHAR(20) NOT NULL, /* 姓名 */
faculty /* 系,應該用什麼型別表示?它包括系名,系主任等若干子屬性 */
...
);
可以看到,如果某個屬性可以繼續分解,那麼是無法在建立資料表時表示它的,所以一般可以成功建立的資料表(前提是語義正確)都是符合第一正規化的要求的
CREATE TABLE student (
student_id INT,
student_name VARCHAR (20),
faculty_name VARCHAR(20),
faculty_boss VARCHAR(20),
PRIMARY KEY (student_id)
);
第二正規化
判斷一個數據表是否滿足第二正規化,可以觀察是否存在非主屬性對於碼的部分函式依賴,方法是
- 找出資料表中所有的碼
- 根據第一步找出的碼,找出所有主屬性
- 在資料表中的所有屬性中去除主屬性,得到非主屬性
- 檢視是否存在某個非主屬性對於碼的部分函式依賴
如果存在部分函式依賴,則這個資料表就不符合第二正規化,解決方法就是模式分解,將違反第二正規化的屬性單獨提出建立一個新表或者分解表使得該表的碼只包含一個屬性
對於部分函式依賴,碼至少要包含兩個屬性,所以上面的student表是滿足第二正規化的,下面考慮另一個表student_course,它描述了學生的選課資訊,包含
- 學生資訊
- 課程名,課程成績
- 學生所在系資訊
CREATE TABLE student_course (
student_id INT NOT NULL,
student_name VARCHAR(20),
course_name VARCHAR(20),
course_score INT,
faculty_name VARCHAR(20),
faculty_boss VARCHAR(20),
PRIMARY KEY (student_id, course_name)
);
由於課程成績必須通過確定是哪個學生的哪門課來獲取,所以這個表的主碼(主鍵)是(student_id, course_name),現在來一步步分析這個表是否符合第二正規化
分析student_course表
第一步,找出資料表中的所有的碼。由上面的分析可得這個表只有唯一的碼(student_id, course_name)
第二步,找出所有的主屬性。碼中的每個屬性都是主屬性,所以主屬性包括student_id和course_name
第三步,找出所有的非主屬性。除去主屬性的都是非主屬性,所以非主屬性包括student_name, course_score, faculty_name, faculty_boss
第四步,判斷非主屬性是否對於碼存在部分函式依賴
每個屬性之間的依賴關係
- student_id可以推匯出student_name,所以student_name完全依賴於student_id
- student_id可以推匯出faculty_name和faculty_boss,所以二者完全依賴於student_id
- (student_id, course_name)可以推匯出course_score,所以course_score完全依賴於(student_id, course_name)
由上述三個關係可以分析出部分依賴關係
- 由於faculty_name完全函式依賴於student_id,所以faculty_name部分函式依賴於(student_id, course_name)
- 由於faculty_boss完全函式依賴於student_id,所以faculty_name部分函式依賴於(student_id, course_name)
- …
所以這個表不滿足第二正規化,可以通過模式分解解決這一問題,比如將課程相關的資訊提出去單獨作為一個表,這樣student_course表的碼就只剩一個屬性student_id了,自然不存在部分函式依賴
CREATE TABLE student (
student_id INT NOT NULL,
student_name VARCHAR(20),
faculty_name VARCHAR(20),
faculty_boss VARCHAR(20) ,
PRIMARY KEY (student_id)
);
CREATE TABLE course (
student_id INT NOT NULL,
course_name VARCHAR(20),
course_score INT,
PRIMARY KEY(student_id, course_name)
);
第三正規化
判斷一個數據表是否滿足第三正規化,可以觀察是否存在非主屬性對於碼的傳遞函式依賴,解決方法也和第二正規化相同,將導致不符合第三正規化的那個屬性提出,單獨建立一個表
可以對上面的student和course表進行分析,判斷這兩個表是否滿足第三正規化
分析course表
第一步,找出所有的碼。course的碼只有(student_id, course_name)
第二步,找出所有的主屬性。主屬性有student_id和course_name
第三步,找出所有的非主屬性。非主屬性有course_score
第四步,判斷是否存在非主屬性對於碼的傳遞函式依賴。因為傳遞函式依賴至少需要有兩個非主屬性,所以course表不存在對於碼的傳遞函式依賴
所以course表滿足第三正規化
分析student表
第一步,找出所有的碼。student的碼只有(student_id)
第二步,找出所有的主屬性。主屬性為student_id
第三步,找出所有的非主屬性。非主屬性有student_name,faculty_name和faculty_boss
第四步,判斷是否存在非主屬性對於碼的傳遞函式依賴。從客觀事實的角度出發,如果知道系名,就可以知道系主任是誰,所以faculty_boss完全函式依賴於faculty_name。又因為faculty_name完全函式依賴於碼student_id,所以faculty_boss傳遞函式依賴於碼student_id
所以student表不滿足第三正規化。
可以通過將系相關的資訊提出去單獨建立一張表,比如
CREATE TABLE student (
student_id INT NOT NULL,
student_name VARCHAR(20),
faculty_name VARCHAR(20),
PRIMARY KEY (student_id)
);
CREATE TABLE faculty (
faculty_name VARCHAR(20) NOT NULL,
faculty_boss VARCHAR(20) NOT NULL,
PRIMARY KEY (faculty_name)
);
BC正規化
BC正規化可以通過判斷是否存在主屬性對於碼的部分函式依賴。出現這種情況的原因通常是由於資料表中存在著多個碼。比如說(A,C)和(B,C)都是這個資料表的碼,同時B完全函式依賴於A,那麼主屬性B就部分函式依賴於碼(A,C),可以通過繼續分解成兩個表分別是
- 表1,包含屬性A,B
- 表2,包含屬性A,C
解決