在本教學中,您將瞭解MySQL外鍵(foreign key)以及如何在MySQL中創建,添加和刪除外鍵約束。
MySQL外鍵簡介
外鍵表示一個表中的一個字段被另一個表中的一個字段引用。外鍵對相關表中的數據造成了限制,使MySQL能夠保持參照完整性。
下麵來看看示例資料庫(zaixiandb)中的以下資料庫中兩個表:customers
和`orders``的ER圖。
上圖中有兩張表:customers
和orders
。每個客戶有零個或多個訂單,每個訂單只屬於一個客戶。customers
表和orders
表之間的關係是一對多的,它是由customerNumber
字段指定在orders
表中建立外鍵(引用customers
表的customerNumber
字段)。orders
表中的customerNumber
字段與customers
表中的customerNumber
主鍵字段相關。
customers
表稱為父表或引用表,orders
表稱為子表或引用表。
表可以有多個外鍵,子表中的每個外鍵可能引用不同的父表。
子表中的行必須包含父表中存在的值,例如,orders
表中的每個訂單記錄必須在customers
表中存在customerNumber
。 因此,多個訂單可以指同一個客戶,因此這種關係稱為一個(客戶)到許多(訂單)或一對多。
有時,子表和父表是一樣的。外鍵返回到表的主鍵,例如以下employees
表:
reportTo
列是一個引用employeeNumber
列的外鍵,employeeNumber
列是employees
表的主鍵,以反映員工之間的報告結構,即每個員工向另一個員工發送的報告和員工可以有零個或多個直接報告。有關如何使用有,請參考自連接教學,以幫助您根據這種表查詢來查詢相關數據。
reportTo
外鍵也稱為遞歸或自引用外鍵。
外鍵執行引用完整性,可以幫助您自動維護數據的一致性和完整性。 例如,不能為不存在的客戶創建訂單。
此外,可以為customerNumber
外鍵設置級聯刪除操作,以便在customers
表中刪除客戶時,與客戶關聯的所有訂單也將被刪除。 這樣可以節省您使用多個DELETE語句或DELETE JOIN語句的時間和精力。
與刪除相同,還可以為customerNumber
外鍵定義級聯更新操作,以執行交叉表更新,而不使用多個UPDATE語句或UPDATE JOIN語句。
在MySQL中,InnoDB存儲引擎支持外鍵,因此您必須創建InnoDB表才能使用外鍵約束。
創建外鍵
MySQL創建外鍵語法
以下語法說明了如何在CREATE TABLE語句中的子表中定義外鍵。
CONSTRAINT constraint_name
FOREIGN KEY foreign_key_name (columns)
REFERENCES parent_table(columns)
ON DELETE action
ON UPDATE action
下麵我們來更詳細的查看上面語法:
CONSTRAINT
子句允許您為外鍵約束定義約束名稱。如果省略它,MySQL將自動生成一個名稱。FOREIGN KEY
子句指定子表中引用父表中主鍵列的列。您可以在FOREIGN KEY
子句後放置一個外鍵名稱,或者讓MySQL為您創建一個名稱。 請注意,MySQL會自動創建一個具有foreign_key_name
名稱的索引。REFERENCES
子句指定父表及其子表中列的引用。 在FOREIGN KEY
和REFERENCES
中指定的子表和父表中的列數必須相同。ON DELETE
子句允許定義當父表中的記錄被刪除時,子表的記錄怎樣執行操作。如果省略ON DELETE
子句並刪除父表中的記錄,則MySQL將拒絕刪除子表中相關聯的數據。此外,MySQL還提供了一些操作,以便您可以使用其他選項,例如ON DELETE CASCADE,當刪除父表中的記錄時,MySQL可以刪除子表中引用父表中記錄的記錄。 如果您不希望刪除子表中的相關記錄,請改用ON DELETE SET NULL
操作。當父表中的記錄被刪除時,MySQL會將子表中的外鍵列值設置為NULL
,條件是子表中的外鍵列必須接受NULL
值。 請注意,如果使用ON DELETE NO ACTION
或ON DELETE RESTRICT
操作,MySQL將拒絕刪除。ON UPDATE
子句允許指定在父表中的行更新時,子表中的行會怎樣執行操作。當父表中的行被更新時,可以省略ON UPDATE
子句讓MySQL拒絕對子表中的行的任何更新。ON UPDATE CASCADE
操作允許您執行交叉表更新,並且當更新父表中的行時,ON UPDATE SET NULL
操作會將子表中行中的值重置為NULL
值。ON UPDATE NO ACTION
或UPDATE RESTRICT
操作拒絕任何更新。
MySQL創建表外鍵示例
以下示例創建一個dbdemo
資料庫和兩個表:categories
和products
。每個類別都有一個或多個產品,每個產品只屬於一個類別。 products
表中的cat_id
字段被定義為具有UPDATE ON CASCADE
和DELETE ON RESTRICT
操作的外鍵。
CREATE DATABASE IF NOT EXISTS dbdemo;
USE dbdemo;
CREATE TABLE categories(
cat_id int not null auto_increment primary key,
cat_name varchar(255) not null,
cat_description text
) ENGINE=InnoDB;
CREATE TABLE products(
prd_id int not null auto_increment primary key,
prd_name varchar(355) not null,
prd_price decimal,
cat_id int not null,
FOREIGN KEY fk_cat(cat_id)
REFERENCES categories(cat_id)
ON UPDATE CASCADE
ON DELETE RESTRICT
)ENGINE=InnoDB;
添加外鍵
MySQL添加外鍵語法
要將外鍵添加到現有表中,請使用ALTER TABLE語句與上述外鍵定義語法:
ALTER table_name
ADD CONSTRAINT constraint_name
FOREIGN KEY foreign_key_name(columns)
REFERENCES parent_table(columns)
ON DELETE action
ON UPDATE action;
MySQL添加外鍵示例
現在,我們添加一個名為vendors
的新表,並更改products
表以包含供應商ID
字段:
USE dbdemo;
CREATE TABLE vendors(
vdr_id int not null auto_increment primary key,
vdr_name varchar(255)
)ENGINE=InnoDB;
ALTER TABLE products
ADD COLUMN vdr_id int not null AFTER cat_id;
要在products
表中添加外鍵,請使用以下語句:
ALTER TABLE products
ADD FOREIGN KEY fk_vendor(vdr_id)
REFERENCES vendors(vdr_id)
ON DELETE NO ACTION
ON UPDATE CASCADE;
現在,products
表有兩個外鍵,一個是引用categories
表,另一個是引用vendors
表。
刪除MySQL外鍵
您還可以使用ALTER TABLE
語句將外鍵刪除,如下語句:
ALTER TABLE table_name
DROP FOREIGN KEY constraint_name;
在上面的聲明中:
- 首先,指定要從中刪除外鍵的表名稱。
- 其次,將約束名稱放在
DROP FOREIGN KEY
子句之後。
請注意,
constraint_name
是在創建或添加外鍵到表時指定的約束的名稱。 如果省略它,MySQL會為您生成約束名稱。
要獲取生成的表的約束名稱,請使用SHOW CREATE TABLE
語句,如下所示:
SHOW CREATE TABLE table_name;
例如,要查看products
表的外鍵,請使用以下語句:
SHOW CREATE TABLE products;
以下是語句的輸出:
CREATE TABLE products (
prd_id int(11) NOT NULL AUTO_INCREMENT,
prd_name varchar(355) NOT NULL,
prd_price decimal(10,0) DEFAULT NULL,
cat_id int(11) NOT NULL,
vdr_id int(11) NOT NULL,
PRIMARY KEY (prd_id),
KEY fk_cat (cat_id),
KEY fk_vendor(vdr_id),
CONSTRAINT products_ibfk_2
FOREIGN KEY (vdr_id)
REFERENCES vendors (vdr_id)
ON DELETE NO ACTION
ON UPDATE CASCADE,
CONSTRAINT products_ibfk_1
FOREIGN KEY (cat_id)
REFERENCES categories (cat_id)
ON UPDATE CASCADE
) ENGINE=InnoDB;
products
表有兩個外鍵約束:products_ibfk_1
和products_ibfk_2
。
可以使用以下語句刪除products
表的外鍵:
ALTER TABLE products
DROP FOREIGN KEY products_ibfk_1;
ALTER TABLE products
DROP FOREIGN KEY products_ibfk_2;
MySQL禁用外鍵檢查
有時,因為某種原因需要禁用外鍵檢查(例如將CSV檔中的數據導入表中)非常有用。 如果不禁用外鍵檢查,則必須以正確的順序加載數據,即必須首先將數據加載到父表中,然後再將數據加載導入到子表中,這可能是乏味的。 但是,如果禁用外鍵檢查,則可以按任何順序加載導入數據。
除非禁用外鍵檢查,否則不能刪除由外鍵約束引用的表。刪除表時,還會刪除為表定義的任何約束。
要禁用外鍵檢查,請使用以下語句:
SET foreign_key_checks = 0;
當然,可以使用以下語句啟用它:
SET foreign_key_checks = 1;
在本教學中,我們已經介紹了很多有關MySQL外鍵的內容。還向您介紹了一些非常方便的語句,允許您在MySQL中有效地管理外鍵。