MySQL中外鍵(FROEIGN KEY)的使用
1.定義:
外鍵用來在兩個表的數據之間建立鏈接,它可以是一列或者多列;一個表可以有一個或多個外鍵。
外鍵對應的是參照完整性,一個表的外鍵可以為空值,若不為空值,則每一個外鍵值必須等於另一個表中主鍵的某個值。
外鍵是表的一個字段,不是表的主鍵,但對應另一個表的主鍵;定義外鍵后,不允許刪除另一個表中具有關聯關系的行。
主表(父表):對於兩個具有關聯關系的表而言,相關聯字段中主鍵所在的那個表即是主表;
從表(子表):對於兩個具有關聯關系的表而言,相關聯字段中外鍵所在的那個表即是從表。
被指向的實體,稱之為主實體(主表),也叫父實體(父表)
負責指向的實體,稱之為從實體(從表),也叫子實體(子表);
若‘表1’的一個列既是主鍵又是外鍵,而這個外鍵約束又對應另一個表‘表2’的主鍵,那么‘表1’和‘表2’就可以合並起來了
2.作用:
外鍵的主要作用是保持數據的一致性、完整性。
如果主表沒有相關的記錄,從表不能插入;
更新時,不能改為主鍵表中沒有的值;
刪除主鍵表記錄時,可以在建外鍵時選定外鍵記錄一起級聯刪除還是拒絕刪除;同樣有級聯更新和拒絕更新的選擇。
ON DELETE CASCADE 級聯刪除
ON UPDATE CASCADE 級聯更新
3.設置MySQL外鍵約束字段的規則:
Ø 父表必須已經存在於數據庫中,或者是當前正在創建的表;若是后者,則父表與子表是同一個表,這樣的表稱為自參照完整性。
Ø 必須為父鍵定義主鍵。
Ø 主鍵不能包含空值,但允許在外鍵中出現空值;也就是說,只要外鍵的每個非空值出現在指定的主鍵中,這個外鍵的內容就是正確的。
Ø 在父表的表名后面指定列名或列名的組合,這個列的組合必須是父鍵的主鍵或者候選鍵。
Ø 外鍵中列的數據類型和父鍵主鍵中對應的數據類型相同。
Ø 外鍵中列的數目必須和父鍵中列的數目相同。
4.創建、添加外鍵的語法規則:
(1) 創建
[CONSTRAINT <外鍵名>] FOREIGN KEY 字段名 [,字段名2,…]
REFERENCES <主表名> 主鍵列1 [,主鍵列2,…]
“外鍵名”為定義的外鍵約束的名稱,一個表中不能有相同名稱的外鍵;
“字段名”表示子表需要添加外鍵約束的字段列;
“主表名”即被子表外鍵所依賴的表的名稱;
“主鍵列”表示主表中定義的主鍵列,或者列組合。
(2) 添加
ALTER TABLE <數據表名> ADD CONSTRAINT <外鍵名> (形如:FK_從表_主表)
FOREIGN KEY (<列名>) REFERENCES <主表名> (<列名>);
實例1:在test_db數據庫中創建employee表和dept表,表結構如下:
Employee表結構
字段名 | 字段說明 | 數據類型 | 主鍵 | 外鍵 | 非空 | 唯一 | 自增 |
---|---|---|---|---|---|---|---|
e_no | 員工編號 | INT(11) | 是 | 否 | 是 | 是 | 否 |
e_name | 員工姓名 | VARCHAR(50) | 否 | 否 | 是 | 否 | 否 |
e_gender | 員工性別 | CHAR(2) | 否 | 否 | 否 | 否 | 否 |
dept_no | 部門編號 | INT(11) | 否 | 是 | 是 | 否 | 否 |
e_job | 職位 | VARCHAR(50) | 否 | 否 | 是 | 否 | 否 |
e_salary | 薪水 | INT(11) | 否 | 否 | 是 | 否 | 否 |
hiredate | 入職日期 | DATE | 否 | 否 | 是 | 否 | 否 |
Dept表結構
字段名 | 字段說明 | 數據類型 | 主鍵 | 外鍵 | 非空 | 唯一 | 自增 |
---|---|---|---|---|---|---|---|
d_no | 部門編號 | INT(11) | 是 | 是 | 是 | 是 | 是 |
d_name | 部門名稱 | VARCHAR(50) | 否 | 否 | 是 | 否 | 否 |
d_location | 部門地址 | VARCHAR(100) | 否 | 否 | 否 | 否 | 否 |
創建數據表dept的SQL語句:
mysql> create table dept
-> (
-> d_no int(11) primary key not null unique auto_increment,
-> d_name varchar(50) not null,
-> d_location varchar(100)
-> );
Query OK, 0 rows affected (0.01 sec)
創建數據表employee,並在表employee上創建外鍵約束,讓它的鍵dept_no作為外鍵關聯到表dept的主鍵d_no,SQL語句如下:
mysql> create table employee
-> (
-> e_no int(11) primary key not null unique,
-> e_name varchar(5) not null,
-> e_gender char(2),
-> dept_no int (11) not null,
-> e_job varchar(50) not null,
-> e_salary int(11) not null,
-> hireDate date not null,
-> constraint fk_dept_employee
-> foreign key(dept_no) references dept(d_no)
-> );
Query OK, 0 rows affected (0.01 sec)
以上語句執行之后,在表employee上添加了名稱為fk_dept_employee的外鍵約束,
外鍵名稱為dept_no,其依賴於表dept的主鍵d_no
#查看表結構:
mysql> show create table employee\G
*************************** 1. row ***************************
Table: employee
Create Table: CREATE TABLE `employee` (
`e_no` int(11) NOT NULL,
`e_name` varchar(5) NOT NULL,
`e_gender` char(2) DEFAULT NULL,
`dept_no` int(11) NOT NULL,
`e_job` varchar(50) NOT NULL,
`e_salary` int(11) NOT NULL,
`hireDate` date NOT NULL,
PRIMARY KEY (`e_no`),
UNIQUE KEY `e_no` (`e_no`),
KEY `fk_dept_employee` (`dept_no`),
CONSTRAINT `fk_dept_employee` FOREIGN KEY (`dept_no`) REFERENCES `dept` (`d_no
`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
/*
關聯指的是在關系數據型數據庫中,相關表之間的聯系。它是通過相同的屬性或屬性組來表示的。子表的外鍵必須關聯父鍵的主鍵,且關鍵字段的數據類型必須匹配,如果類型不一樣,則創建子表時會出現錯誤” ERROR 1005 (HY000): Can't create table 'database.tablename' (errno: 150)”。
mysql> alter table employee
-> add constraint fk_dept_employee
-> foreign key(dept_no)
-> references dept(d_no);
ERROR 1005 (HY000): Can't create table 'test_db.#sql-888_1' (errno: 150)
*/
實例2:在數據庫’test_db1’中創建數據表employee和dept,修改數據表 employee,將字段dept_no設置為外鍵,與數據表dept的主鍵d_no進行關聯,SQL語句如下;
mysql> create table employee
-> (
-> e_no int(11) primary key not null unique,
-> e_name varchar(50) not null,
-> e_gender char(2),
-> dept_no int(11) not null,
-> e_job varchar(50) not null,
-> e_salary int(11) not null,
-> hiredate date not null
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> create table dept
-> (
-> d_no int(11) primary key not null unique auto_increment,
-> d_name varchar(50) not null,
-> d_location varchar(100)
-> );
Query OK, 0 rows affected (0.01 sec)
#添加外鍵約束:
mysql> alter table employee
-> add constraint fk_dept_employee
-> foreign key(dept_no)
-> references dept(d_no);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
#查看表結構:
mysql> show create table employee\G
*************************** 1. row ***************************
Table: employee
Create Table: CREATE TABLE `employee` (
`e_no` int(11) NOT NULL,
`e_name` varchar(50) NOT NULL,
`e_gender` char(2) DEFAULT NULL,
`dept_no` int(11) NOT NULL,
`e_job` varchar(50) NOT NULL,
`e_salary` int(11) NOT NULL,
`hiredate` date NOT NULL,
PRIMARY KEY (`e_no`),
UNIQUE KEY `e_no` (`e_no`),
KEY `fk_dept_employee` (`dept_no`),
CONSTRAINT `fk_dept_employee` FOREIGN KEY (`dept_no`) REFERENCES `dept` (`d_no
`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
5.刪除外鍵:
ALTER TABLE <表名> DROP FOREIGN KEY <外鍵約束名>;
(外鍵一旦刪除,就會解除主表和從表間的關聯關系)
mysql> alter table employee drop foreign key fk_dept_employee;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table employee\G;
*************************** 1. row ***************************
Table: employee
Create Table: CREATE TABLE `employee` (
`e_no` int(11) NOT NULL,
`e_name` varchar(5) NOT NULL,
`e_gender` char(2) DEFAULT NULL,
`dept_no` int(11) NOT NULL,
`e_job` varchar(50) NOT NULL,
`e_salary` int(11) NOT NULL,
`hireDate` date NOT NULL,
PRIMARY KEY (`e_no`),
UNIQUE KEY `e_no` (`e_no`),
KEY `fk_dept_employee` (`dept_no`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
6.外鍵約束的三種形式:
(1) district:嚴格模式(默認),父表不能刪除或更新一個已經被子表數據引用的記錄。
mysql> delete from departments where d_no=1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constrai
nt fails (`yggl`.`employee`, CONSTRAINT `fk_dept_emp` FOREIGN KEY (`dept_no`) RE
FERENCES `departments` (`d_no`))
(2) cascade:級聯模式,父鍵的操作,對應子表關聯的數據也跟着操作。
(3) set null:置空模式,父表被操作之后,子表對應的外鍵字段被置空。
通常情況下,合理的模式應該是這樣:刪除父表中的數據,子表置空;更新父表的時候,子表做級聯操作。(foreign key(外鍵字段) references 父鍵(外鍵字段) on delete set null on update cascade)
指定模式的語法:
foreign key(外鍵字段) references 父表(外鍵字段) on delete 模式 on update 模式