數據庫有三大范式和BC范式,我們來詳細探討一下:
首先三大范式:
第一范式
第一范式(1NF):表中所有屬性都不能再分,都應該是原子值。
這也是數據表的最低的最基本的要求。
第二范式
第二范式(2NF):在滿足第一范式的前提下,還要求每一個非主屬性都要完全依賴於任何一個候選碼。
上面這句話聽起來比較抽象,其實也好理解。(下面的主鍵(限第二范式中)其實指:主鍵或候選碼,這么寫的看起來太繞就簡寫成主鍵了,大家注意一下)
它的意思就是指,每一個非主屬性都應該和主鍵有關(不能只和主鍵的一部分相關,這是指聯合主鍵),即一個表只做一件事。
舉個例子,下面是一個關系,
Student(Sno, Sdept, Sloc, Cno, Grade)
- Sno:學號
- Sdept:學生所在的系
- Sloc:學生的住處,每個系的學生住在一起
- Cno:課程編號
- Grade:該學生該課程的成績
其中該關系的主鍵為(Sno, Cno)
顯然該關系就不符合第二范式,而這樣會出現很多的問題。
(1)插入異常
如果要插入一個學生,但是該學生還未選課,那么他就沒有Cno,而主鍵又不能為空,那么他就插不進去…
(2)刪除異常
假設一個學生本來只選了一門課,現在他一門課都不想選了,想把這門課退掉,那么這個學生的所有信息也會隨之而被刪掉…
(3)修改復雜
如果一個學生轉系了,那么修改起來就很麻煩,冗余數據很多。本來只要改Sdept就行了,但是現在還需要對它的Sloc進行修改,而且如果他選了5門課,則需要修改Sdept
和Sloc
五次。
所以應該將其分成兩個表:
CJ(Sno,Cno,Grade) /*成績表*/
StudentInfo(Sno,Sdept,Sloc) /*學生基礎信息表*/
第三范式
第三范式(3NF):在滿足第二范式的前提下,還要求表中不存在傳遞依賴,即表中每一列都要與主鍵直接相關,而非間接相關。
舉個栗子:
訂單表(訂單號, 訂購日期, 顧客編號, 顧客名)
上面表中,顯然訂單號是主鍵,而顧客名與訂單號卻是間接相關的,他們中間通過顧客編號相連。
這顯然是不滿足第三范式的,因此需要將其進行修改:
訂單表(訂單號,訂購日期,顧客編號)
顧客表(顧客編號,顧客名)
這樣顯然也是一種避免冗余的手段。
如何區分這三種范式呢?
第一范式:表中的每一列都是最小的單元,任何一列都不能再進行拆分了;
第二范式:表中所有的列都應該是和主鍵(的全體)完全相關的,即不能只和主鍵的某一部分相關;
第三范式:表中每一個非主屬性都要和主鍵直接相關,即不要在表中出現太多另外一個實體的信息,只需要出現它的id就行了。
范式之所以叫做范式,就是因為它給數據庫的設計提供了一種規范,能夠最大可能的避免犯錯,也減少了數據的冗余,提高數據庫效率。
附加:BC范式(BCNF)
數據庫的三大范式只是最基本的,而BC范式也常與他們放到一起討論,因為BCNF也被稱為修正的第三范式,又或者說是擴充的第三范式。
為什么叫修正的第三范式?那么表示第三范式肯定有所缺漏,那么缺漏是什么呢?又如何補救呢?
我們看到第三范式的要求是每一個非主屬性都要直接依賴於主屬性,看似完美,可是如果除了主屬性外,還有一個候選碼呢?
顯然從定義可以知道,這個主屬性肯定能和候選碼一一對應的,那這樣豈不是又會造成冗余?
覺得很抽象嗎?舉個例子:
倉庫(倉庫編號,貨物編號,倉庫管理員編號)
其中每一個倉庫管理員只管理一個倉庫。
那么我們可以發現這里其實主碼可以有兩種,分別是:
- (倉庫編號) 可唯一確定 (倉庫管理員編號,貨物編號)
- (倉庫管理員編號) 可唯一確定 (倉庫編號,貨物編號)
必須要承認上述關系是符合第三范式的吧,但是有沒有覺得這樣倉庫管理員編號會出現大量的沒必要的冗余啊,因此BC范式就是解決這個問題的,需要將其改為兩個表,順便可以將貨物的數量加進來。
至於為什么上面關系中我不將貨物數量加進來,是因為一旦加進來后那個關系就不符合第二范式了,想想看,如果加入貨物數量,那么主鍵就變成了(倉庫編號,貨物編號)
,可是倉庫管理員只與倉庫編號有關,不依賴於貨物編號了呀,就不構成對主鍵的完全依賴關系了。
下面放上BC范式的修改版:
倉庫與管理員表(倉庫編號,倉庫管理員編號)
倉庫貨物表(倉庫編號,貨物編號,貨物數量)
參考資料:
https://www.cnblogs.com/waj6511988/p/7027127.html
https://blog.csdn.net/javanotes/article/details/81368715
https://www.cnblogs.com/knowledgesea/p/3667395.html
https://blog.csdn.net/u014458048/article/details/56678698