一:
一對多
當我們用主鍵唯一標識記錄時,我們就可以在students表中確定任意一個學生的記錄:
id name other columns...
1 小明 ...
2 小紅 ...
我們還可以在classes表中確定任意一個班級記錄:
id name other columns...
1 一班 ...
2 二班 ...
但是我們如何確定students表的一條記錄,例如,id=1的小明,屬于哪個班級呢?
由于一個班級可以有多個學生,在關系模型中,這兩個表的關系可以稱為“一對多”,即一個classes的記錄可以對應多個students表的記錄。
為了表達這種一對多的關系,我們需要在students表中加入一列class_id,讓它的值與classes表的某條記錄相對應:
id class_id name other columns...
1 1 小明 ...
2 1 小紅 ...
5 2 小白 ...
這樣,我們就可以根據(jù)class_id這個列直接定位出一個students表的記錄應該對應到classes的哪條記錄。
例如:
小明的class_id是1,因此,對應的classes表的記錄是id=1的一班;
小紅的class_id是1,因此,對應的classes表的記錄是id=1的一班;
小白的class_id是2,因此,對應的classes表的記錄是id=2的二班。
在students表中,通過class_id的字段,可以把數(shù)據(jù)與另一張表關聯(lián)起來,這種列稱為外鍵。
外鍵并不是通過列名實現(xiàn)的,而是通過定義外鍵約束實現(xiàn)的:
ALTER TABLE students
ADD CONSTRAINT fk_class_id
FOREIGN KEY (class_id)
REFERENCES classes (id);
其中,外鍵約束的名稱fk_class_id可以任意,F(xiàn)OREIGN KEY (class_id)指定了class_id作為外鍵,REFERENCES classes (id)指定了這個外鍵將關聯(lián)到classes表的id列(即classes表的主鍵)。
通過定義外鍵約束,關系數(shù)據(jù)庫可以保證無法插入無效的數(shù)據(jù)。即如果classes表不存在id=99的記錄,students表就無法插入class_id=99的記錄。
由于外鍵約束會降低數(shù)據(jù)庫的性能,大部分互聯(lián)網(wǎng)應用程序為了追求速度,并不設置外鍵約束,而是僅靠應用程序自身來保證邏輯的正確性。這種情況下,class_id僅僅是一個普通的列,只是它起到了外鍵的作用而已。
要刪除一個外鍵約束,也是通過ALTER TABLE實現(xiàn)的:
ALTER TABLE students
DROP FOREIGN KEY fk_class_id;
注意:刪除外鍵約束并沒有刪除外鍵這一列。刪除列是通過DROP COLUMN ...實現(xiàn)的。
二
多對多
通過一個表的外鍵關聯(lián)到另一個表,我們可以定義出一對多關系。有些時候,還需要定義“多對多”關系。例如,一個老師可以對應多個班級,一個班級也可以對應多個老師,因此,班級表和老師表存在多對多關系。
多對多關系實際上是通過兩個一對多關系實現(xiàn)的,即通過一個中間表,關聯(lián)兩個一對多關系,就形成了多對多關系:
teachers表:
id name
1 張老師
2 王老師
3 李老師
4 趙老師
classes表:
id name
1 一班
2 二班
中間表teacher_class關聯(lián)兩個一對多關系:
id teacher_id class_id
1 1 1
2 1 2
3 2 1
4 2 2
5 3 1
6 4 2
通過中間表teacher_class可知teachers到classes的關系:
id=1的張老師對應id=1,2的一班和二班;
id=2的王老師對應id=1,2的一班和二班;
id=3的李老師對應id=1的一班;
id=4的趙老師對應id=2的二班。
同理可知classes到teachers的關系:
id=1的一班對應id=1,2,3的張老師、王老師和李老師;
id=2的二班對應id=1,2,4的張老師、王老師和趙老師;
因此,通過中間表,我們就定義了一個“多對多”關系。
3:
一對一
一對一關系是指,一個表的記錄對應到另一個表的唯一一個記錄。
例如,students表的每個學生可以有自己的聯(lián)系方式,如果把聯(lián)系方式存入另一個表contacts,我們就可以得到一個“一對一”關系:
id student_id mobile
1 1 135xxxx6300
2 2 138xxxx2209
3 5 139xxxx8086
有細心的童鞋會問,既然是一對一關系,那為啥不給students表增加一個mobile列,這樣就能合二為一了?
如果業(yè)務允許,完全可以把兩個表合為一個表。但是,有些時候,如果某個學生沒有手機號,那么,contacts表就不存在對應的記錄。實際上,一對一關系準確地說,是contacts表一對一對應students表。
還有一些應用會把一個大表拆成兩個一對一的表,目的是把經(jīng)常讀取和不經(jīng)常讀取的字段分開,以獲得更高的性能。例如,把一個大的用戶表分拆為用戶基本信息表user_info和用戶詳細信息表user_profiles,大部分時候,只需要查詢user_info表,并不需要查詢user_profiles表,這樣就提高了查詢速度。
4:
小結
關系數(shù)據(jù)庫通過外鍵可以實現(xiàn)一對多、多對多和一對一的關系。外鍵既可以通過數(shù)據(jù)庫來約束,也可以不設置約束,僅依靠應用程序的邏輯來保證。