MySQL 的外鍵約束實作在以下幾個主要方面與 SQL 標準不同:
如果父資料表中有數個具有相同參考鍵值的列,
InnoDB
執行外鍵檢查時,會假設其他具有相同鍵值的父列不存在。例如,如果您定義RESTRICT
類型的約束,並且有一個子列與多個父列相關聯,則InnoDB
不允許刪除任何父列。以下範例說明了這一點:mysql> CREATE TABLE parent ( -> id INT, -> INDEX (id) -> ) ENGINE=InnoDB; Query OK, 0 rows affected (0.04 sec) mysql> CREATE TABLE child ( -> id INT, -> parent_id INT, -> INDEX par_ind (parent_id), -> FOREIGN KEY (parent_id) -> REFERENCES parent(id) -> ON DELETE RESTRICT -> ) ENGINE=InnoDB; Query OK, 0 rows affected (0.02 sec) mysql> INSERT INTO parent (id) -> VALUES ROW(1), ROW(2), ROW(3), ROW(1); Query OK, 4 rows affected (0.01 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> INSERT INTO child (id,parent_id) -> VALUES ROW(1,1), ROW(2,2), ROW(3,3); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> DELETE FROM parent WHERE id=1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE RESTRICT)
如果
ON UPDATE CASCADE
或ON UPDATE SET NULL
遞迴更新在相同串聯期間先前更新的相同資料表,它的行為會類似於RESTRICT
。這表示您無法使用自我參照的ON UPDATE CASCADE
或ON UPDATE SET NULL
作業。這是為了防止因串聯更新而導致無限迴圈。另一方面,自我參照的ON DELETE SET NULL
是可行的,自我參照的ON DELETE CASCADE
也是如此。串聯操作的巢狀深度不得超過 15 層。在插入、刪除或更新多個列的 SQL 語法中,外鍵約束(如同唯一約束)會逐列檢查。
InnoDB
在執行外鍵檢查時,會在它必須檢查的子記錄或父記錄上設定共用列級鎖定。MySQL 會立即檢查外鍵約束;檢查不會延遲到交易提交。根據 SQL 標準,預設行為應該是延遲檢查。也就是說,約束只有在處理完整個 SQL 語法後才會進行檢查。這表示不可能使用外鍵刪除參考自身的列。沒有任何儲存引擎(包括
InnoDB
)會辨識或強制執行參考完整性約束定義中使用的MATCH
子句。使用明確的MATCH
子句不會產生指定的效果,並且會導致ON DELETE
和ON UPDATE
子句被忽略。應該避免指定MATCH
。SQL 標準中的
MATCH
子句控制當與參考資料表中的主鍵比較時,如何處理複合(多欄)外鍵中的NULL
值。MySQL 本質上實作了MATCH SIMPLE
定義的語意,允許外鍵為全部或部分NULL
。在這種情況下,即使包含此外鍵的(子資料表)列與參考(父)資料表中沒有任何列相符,也可以插入該列。(可以使用觸發器來實作其他語意。)參考非
UNIQUE
鍵的FOREIGN KEY
約束不是標準 SQL,而是InnoDB
擴充功能,現在已棄用,而且必須透過設定restrict_fk_on_non_standard_key
來啟用。您應該預期在未來版本的 MySQL 中移除對使用非標準鍵的支援,並且現在就開始從這些鍵遷移。NDB
儲存引擎需要每個做為外鍵參考的欄位上都有明確的唯一鍵(或主鍵),這符合 SQL 標準。對於不支援外鍵的儲存引擎(例如
MyISAM
),MySQL 伺服器會解析並忽略外鍵規格。MySQL 會解析但忽略(如 SQL 標準中定義)在定義參考做為欄位規格一部分的「“內嵌
REFERENCES
規格”」。MySQL 僅接受指定為單獨FOREIGN KEY
規格一部分的REFERENCES
子句。定義欄位以使用
REFERENCES
子句沒有實際效果,而且僅作為提醒或註解,告訴您目前正在定義的欄位是要參考另一個資料表中的欄位。在使用此語法時,務必瞭解:tbl_name
(col_name
)MySQL 不會執行任何類型的檢查,以確定
col_name
實際上是否存在於tbl_name
中(甚至tbl_name
本身是否存在)。MySQL 不會對
tbl_name
執行任何類型的動作,例如在您正在定義的資料表中的列上執行動作時刪除列;換句話說,此語法不會產生任何ON DELETE
或ON UPDATE
行為。(雖然您可以在REFERENCES
子句中撰寫ON DELETE
或ON UPDATE
子句,但也會被忽略。)此語法會建立一個欄位;它不會建立任何類型的索引或索引鍵。
您可以將如此建立的欄位用作聯結欄位,如下所示:
CREATE TABLE person ( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, name CHAR(60) NOT NULL, PRIMARY KEY (id) ); CREATE TABLE shirt ( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, style ENUM('t-shirt', 'polo', 'dress') NOT NULL, color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL, owner SMALLINT UNSIGNED NOT NULL REFERENCES person(id), PRIMARY KEY (id) ); INSERT INTO person VALUES (NULL, 'Antonio Paz'); SELECT @last := LAST_INSERT_ID(); INSERT INTO shirt VALUES ROW(NULL, 'polo', 'blue', @last), ROW(NULL, 'dress', 'white', @last), ROW(NULL, 't-shirt', 'blue', @last); INSERT INTO person VALUES (NULL, 'Lilliana Angelovska'); SELECT @last := LAST_INSERT_ID(); INSERT INTO shirt VALUES ROW(NULL, 'dress', 'orange', @last), ROW(NULL, 'polo', 'red', @last), ROW(NULL, 'dress', 'blue', @last), ROW(NULL, 't-shirt', 'white', @last); SELECT * FROM person; +----+---------------------+ | id | name | +----+---------------------+ | 1 | Antonio Paz | | 2 | Lilliana Angelovska | +----+---------------------+ SELECT * FROM shirt; +----+---------+--------+-------+ | id | style | color | owner | +----+---------+--------+-------+ | 1 | polo | blue | 1 | | 2 | dress | white | 1 | | 3 | t-shirt | blue | 1 | | 4 | dress | orange | 2 | | 5 | polo | red | 2 | | 6 | dress | blue | 2 | | 7 | t-shirt | white | 2 | +----+---------+--------+-------+ SELECT s.* FROM person p INNER JOIN shirt s ON s.owner = p.id WHERE p.name LIKE 'Lilliana%' AND s.color <> 'white'; +----+-------+--------+-------+ | id | style | color | owner | +----+-------+--------+-------+ | 4 | dress | orange | 2 | | 5 | polo | red | 2 | | 6 | dress | blue | 2 | +----+-------+--------+-------+
以這種方式使用時,
REFERENCES
子句不會顯示在SHOW CREATE TABLE
或DESCRIBE
的輸出中。mysql> SHOW CREATE TABLE shirt\G *************************** 1. row *************************** Table: shirt Create Table: CREATE TABLE `shirt` ( `id` smallint(5) unsigned NOT NULL auto_increment, `style` enum('t-shirt','polo','dress') NOT NULL, `color` enum('red','blue','orange','white','black') NOT NULL, `owner` smallint(5) unsigned NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
如需外鍵約束的資訊,請參閱 章節 15.1.20.5,「FOREIGN KEY 約束」。