實體-聯系模型
基本概念
-
實體:實體是有別於其他對象的一個事物,比如人,教師,學生,課程,專業。
-
實體集:一系列實體組成的集合,在數據庫中對應的就是一個表。
-
屬性:一組屬性構成一個實體,比如學生可能具有學號,姓名,年齡等屬性。每個實體中的屬性都有一個值。
所以一個數據庫中包含若干個實體集,每個實體集中有若干個實體,每個實體中有一些屬性。
-
聯系:多個實體之間相互關聯,比如教師Katz和學生Shankar可能存在一個聯系advisor,表示Katz是Shankar的老師
-
聯系集:相同類型聯系的集合。如果\(E_1,E_2,E_3,...,E_n\)是實體集,聯系集R是如下集合的一個子集,\(n>=2, (e_1, e_2, ... , e_n)\)是其中的一個聯系。
\[\left \{ (e_1,e_2,...,e_n) | e_1\in E_1, e_2\in E_2,..., e_n\in E_n\right \} \]說白了,聯系集就是咱們用數據庫時建的那些用來聯系兩個表的表,比如選課表用來聯系學生和課程之間的一個關系。而這個聯系用數學表示就是\((student\_id, course\_id)\),所有這些元組就組成了聯系集\(\left \{(student\_id, course\_id) | student\_id \in student, course\_id \in course \right \}\),也就是選課表。
-
參與:實體集之間的關聯稱為參與,比如一個學生Shankar和一門課程Comp. Sci.共同參與到選課這個聯系中。
-
聯系實例:兩個實體集中的實體參與到一個聯系中時,就構成了一個聯系實例,比如學生Shankar選了Comp. Sci.課程,那么它們就構成了選課聯系中的一個聯系實例。
-
角色:實體在聯系中充當的功能。
-
描述性屬性:聯系中可以具有一些描述性屬性,比如通過一個date來記錄學生在何時選了一門課。
-
聯系集的度:參與聯系集的實體集個數,一般情況下聯系集的度為2,稱為二元聯系集。
屬性
簡單屬性和復合屬性
之前的屬性都是簡單屬性,就是只有一個值的屬性,復合屬性可以繼續划分稱更小的屬性。
比如name可以划分為first_name,middle_name和last_name。
復合屬性是可以嵌套的,例如下面的address可以划分為street,city等屬性,而street又可以划分為street_number、street_name、apartment_number屬性
單值屬性和多值屬性
有的屬性只有一個值,比如一個人的age,只能有一個,不存在一個人有多個年齡,而電話號,一個人可以有多個。
多值屬性用花括號擴起,比如{phone_number}
。
派生屬性
可以通過其他相關屬性計算出來,比如教師有一個屬性是教了多少學生,這個可以根據教師關聯的學生數統計出來。
再比如用戶有birth
字段代表他的生日,那么age
字段就可以是一個派生屬性,因為它可以從birth
推算出來。
映射基數
映射基數是一個實體能通過聯系集映射實體的個數。
- 一對一:A中的一個實體最多只能與B中的一個實體相關聯,B中的一個實體最多也只能與A中的一個實體相關聯。
- 一對多:A中的一個實體可以與B中的多個實體相關聯,B中的一個實體至多與A中的一個實體相關聯。
- 多對一:A中的多個實體之多與B中的一個實體相關聯,B中的一個實體可以與A中的多個實體相關聯。
- 多對多:A中的實體可以與B的多個實體相關聯,B中的多個實體也可以與A的多個實體相關聯。
參與約束
如果實體集E中的每個實體都參與到聯系集R中,稱E在R中的參與是全部的。如果非全部,則稱部分的。
我們希望每個學生都參與到advisor聯系中,這證明它們都有一個老師,而對於老師它們並不一定都參與到advisor中,因為有的老師可能不教學生,而是從事一些學校的其他工作。
碼
和關系中的碼概念一致。
設R是涉及實體集\(E_1, E_2, ..., E_n\)的聯系集,若實體集中的主碼屬性名互不相同,那么:
構成了聯系集R中的一個聯系,\(primary-key(E)\)代表實體集E中的主碼,\({a_1, a_2, ... ,a_n}\)是聯系集自有的描述性屬性。
意思就是,參與聯系集的所有實體集的主碼和聯系集自有的所有屬性構成了聯系集中的一個聯系。
不管怎樣,以下屬性集合代表了聯系集的一個超碼。
聯系集的主碼結構依賴於聯系集的映射基數。比如advisor聯系集是學生到他的老師的聯系,如果是多對多關系,那么只有學生的主碼和老師的主碼的並集能組成聯系集的主碼。而如果一個學生只有一個老師,那么學生的主碼足以表示聯系集的主碼。如果老師和學生是多對一關系,那么老師(多的一方)即可作為聯系集的主碼。
刪除冗余屬性
之前的大學系統里,有很多冗余屬性。
比如instructor
中有dept_name
,department
中也有dept_name
,二者的聯系通過instructor
中的一個字段來表現。
這樣也會出現一些問題,我們沒法表示一個還沒有所在系的教師,我們沒法表示有兩個所在系的教師等。
它們兩個之間的聯系應該通過一個聯系集來定義。
inst_dept (ID, dept_name)
inst_dept
存儲了來自兩個實體集instructor
和dept_name
的聯系集。現在,我們可以從instructor
中刪除dept_name
字段。
經過刪除冗余屬性並創建聯系集表,我們得到了如下的大學數據庫關系模型。
實體集
聯系集
實體聯系圖(ER圖)
基本結構
- 分成兩部分的矩形代表實體集,上面是實體集的名字,下面是屬性名
- 菱形代表聯系集
- 未分割的矩形代表聯系集的屬性
- 下划線標注的屬性是主碼
- 線段將實體集連接到聯系集
- 虛線將聯系集屬性屬性連接到聯系集
- 雙線顯示實體在聯系集中的參與度
- 雙菱線代表連接到弱實體集的標志性聯系集
映射基數
使用帶箭頭的線段代表一,不帶箭頭的線段代表多。
如果想對映射基數做更細致的限制,可以使用l..h
來指定雙方最少最多有多少個實體參與映射。
當l..h
左邊的數為1時,代表該實體集中每個實體最少參與一次聯系,也就是說該實體集全部參與聯系。當右面為*
時,代表該實體集中的每個實體可以參與任意多次聯系。
上圖的instructor
代表教師可以有任意多個學生(也可以沒有),所以instructor
到student
是一對多聯系。而student
最少和最多都只能參與一次聯系,這證明學生必須有一個老師且只能有一個老師。student
在聯系advisor
中的參與是全部的。
這種關系可以使用從student
畫一條到advisor
的雙線,並且從advisor
畫到instructor
的箭頭實線來代表7-10
中的關系。
復雜的屬性
上圖是如何在ER圖中表示復合屬性、多值屬性和派生屬性的示例。
name
、address
、street
都是復合屬性,{phone_number}
是多值屬性、age()
是派生屬性。
角色
一般情況下,聯系集包含被聯系表的主碼的並集,而且這些主碼名字不相同,所以我們不用顯式指定角色就能夠分辨。
下面這個情況就不行了,prereq
代表從course
到course
的一個聯系集,用來說明兩門課程之間的先修關系。
這時,聯系集是由相同的兩個實體構成的,它們的主碼是一致的,我們沒法分辨哪個是哪個,所以可以在連線上通過文字來給參與聯系的實體集中的實體賦予一個角色,下圖賦予了course_id
和prereq_id
的角色。
弱實體集
比如section
開課實體,它有course_id, semester, year
組成,就是課程編號,學期,學年。section
中的所有屬性構成了section
的主碼,它們才能唯一確定一個選課,但如果這時你想要創建一個section
實體到course
實體的聯系sec_course
,你會發現sec_course
的信息是冗余的,但如果不創建這個聯系,又會讓二者的聯系隱含section
實體集的一個屬性中,這讓我們的ER圖不清晰。
消除冗余的辦法就是在section
中不保存course_id
,放到sec_course
中。然后現在,section
實體便不具有能夠唯一標識自己的碼了,而是通過聯系集sec_course
為section
提供唯一標識自己的額外信息。這種不具有能夠形成主碼的屬性的實體集稱為弱實體集(weak entity set)。
注意,這里之前我看的很迷糊,有很多問題,比如:
sec_course
是如何和section
聯系上的- 這種結構如何在數據庫中實現
其實ER圖不代表最終數據庫中的結構,數據庫中的結構還是最開始那樣從section
種存儲course_id
,而ER圖為了將數據庫結構以清晰的方式表述出來,所以才引入弱實體集的概念,否則很難以在圖中看出section
實體集與course
實體集有關聯。
有主碼的實體集稱為強實體集(strong entity set)
弱實體集必須與一個強實體集產生關聯才有意義,就比如section
必須和course
關聯才有意義,這個強實體集稱作標識(identifying),或屬主實體集(owner entity set)
可以說弱實體集存在依賴(existence dependent)於標識實體集,標識實體集擁有(own)它所標識的弱實體集,將弱實體集與其標識實體集相聯系的聯系稱為標識性聯系(identifying relationship)。
弱實體集中的屬性,在剛剛的例子中是semester, year
稱作弱實體集的分辨符,它們雖不能標識唯一的一次開課,但也在聯系中起到了一定的分辨作用,比如同一門課在不同時間的開課,分辨符構成了弱實體集的部分碼,弱實體集的主碼由標識實體集主碼加上弱實體集部分碼組成,也就是course_id, semester, year
。
如下是弱實體集在ER圖中的畫法
- 弱實體集的分辨符用虛線標注(第一個分辨符我划掉了,怕難以理解)
- 標識性聯系用菱形雙線繪制。
這個圖還表明了弱實體集在聯系中是全部參與的,因為弱實體只有關聯到強實體才有意義,一門沒關聯到任何課程的開課信息有什么意義?
大學系統的ER圖
轉換為關系模式
強實體集
簡單屬性
直接轉換,主碼一致
復合屬性
把復合屬性依次展開,比如name
展開后就是first_name
、middle_initial
、last_name
,並且復合屬性本身並不會出現在關系模式中
多值屬性
多值屬性需要創建新的關系模式,比如教師可以有多個手機號,那就要創建出一個新的關系模式instructor_phone
,它的主碼由所有屬性組成,ID是參照instructor
的外鍵
弱實體集
弱實體集的模式由它所依賴的標識實體集的主碼和自身的分辨符組成。標識實體集的主碼是弱實體集的一個外碼。
弱實體集與強實體集之間的聯系集在關系模式中是冗余的,不必給出。
聯系集
聯系集確定主碼:
- 多對多的二元聯系,兩個實體集的主碼並集成為聯系集主碼
- 一對一的二元聯系,兩個實體集任意一個主碼成為聯系集主碼
- 一對多或多對一的二元聯系,參與聯系中“多”的那一方的主碼成為聯系集的主碼
- 沒有箭頭的n元聯系集,所有實體集的主碼並集成為聯系集主碼
- 有一個箭頭的n元聯系集,不被箭頭所指的所有實體集的主碼並集成為聯系集的主碼
參與聯系的實體集的主碼都會變成聯系集的外碼。
模式合並
在一對一的情況下,如果實體集A,B以及二者的聯系集AB中,A全部參與AB,那么可以將A和AB合並成一個模式。
比如inst_dept
記錄所有教員的系,教員必定有一個所在系,所以instructor
在inst_dept
中全部參與,那么可以將實體集和聯系集合並,得到{ID, name, dept_name, salary}
然后,聯系集上的外碼約束移動到了合並后的關系模式上。