外键

**外來鍵**又稱**外部鍵**，是指在關聯式資料庫中，每個資料表都是由關聯來連繫彼此的關係，父資料表（Parent Entity）的主鍵（Primary Key）會放在另一個資料表，當做屬性以建立彼此的關聯，而這個屬性就是外來鍵。

比如，學生跟老師之間是教學的關聯，學生資料表會有個屬性叫指導老師 (FK)，而這個值就是對應到老師資料表的老師代號 (PK)，學生的指導老師就是外來鍵。

外來鍵是表中的一組特性，它參照另一個表的主鍵。外來鍵連結這兩個表。另一種說法：在關聯式資料庫的上下文中，外來鍵是一組受某種包含依賴約束的特性，特別是由一個關係 R 中的外來鍵特性組成的元組必須也存在於其他一些（不一定是不同的）關係 S 中，而且這些屬性也必須是 S 中的候選鍵。簡而言之，外來鍵是一組參照候選鍵的特性。 例如，名為 TEAM 的表可能有一個屬性 MEMBER\_NAME，它參照 PERSON 表中的候選鍵 PERSON\_NAME 作為外來鍵。 由於 MEMBER\_NAME 是一個外來鍵，任何在 TEAM 中作為成員名稱存在的值也必須作為人名存在於 PERSON 表中； 換句話說，一個團隊的每個成員也是一個人。

## 概述

包含外來鍵的表稱為子表 (child table)，包含候選鍵的表稱為「**被參照表**」(referenced) 或父表 (parent table)。在資料庫關係建模和實現中，候選鍵是一組零個或多個特性，其值對於關係中的每個元組（行）保證是唯一的。任何元組的候選鍵特性的值或值組合不能與該關係中的任何其他元組重複。

由於外來鍵的目的是標識被參照表的某一行，所以一般要求外來鍵等於主表某行的候選鍵，否則沒有值（NULL）。此規則稱為兩個表之間的參照完整性約束。因為違反這些約束可能是許多資料庫問題的根源，所以大多數資料庫管理系統提供了確保每個非空外來鍵對應於參照表的一行的機制。

例如，考慮一個包含兩個表的資料庫：一個包含所有客戶資料的 CUSTOMER 表和一個包含所有客戶訂單的 ORDER 表。假設業務要求每個訂單必須指向一個客戶。為了在資料庫中反映這一點，在 ORDER 表中添加了一個外來鍵列（例如 CUSTOMERID），它參照了 CUSTOMER 的主鍵（例如 ID）。因為表的主鍵必須是唯一的，並且因為 CUSTOMERID 僅包含來自該主鍵欄位的值，所以我們可以假設，當它具有值時，CUSTOMERID 將標識出下訂單的特定客戶。但是，如果在刪除 CUSTOMER 表的行或更改 ID 列時 ORDER 表沒有保持最新，則上述約束不再保證成立，並且使用這些表可能會變得更加困難。許多現實世界的資料庫通過「停用」而不是物理刪除主表外來鍵，或者通過複雜的更新程式來解決這個問題，這些程式在需要更改時修改對外來鍵的所有參照。

外來鍵在資料庫設計中起著至關重要的作用。資料庫設計的一個重要部分是確保真實世界實體之間的關係通過參照反映在資料庫中，使用外來鍵從一個表參照到另一個表。資料庫設計的另一個重要部分是資料庫規格化，其中表被分解並且外來鍵使得它們可以被重構。

參照表（或子表）中的多行可能參照到被參照表（或父表）中的同一行。在這種情況下，兩個表之間的關係稱為參照表和被參照表之間的一對多關係。

此外，實際上，子表和父表可能是同一張表，即外來鍵指向同一張表。這種外來鍵在 SQL:2003 中稱為**自參照**(self-referencing) 或**遞迴外來鍵**(recursive foreign key)。在資料庫管理系統中，這通常是通過將第一個和第二個參照連結到同一個表來完成的。

一個表可能有多個外來鍵，每個外來鍵可以有不同的父表。每個外來鍵都由資料庫系統獨立執行。因此，可以使用外來鍵建立表之間的級聯關係。

外來鍵定義為關係中的一個特性或一組特性，其值與另一個關係中的主鍵匹配。將此類約束添加到現有表的語法在 SQL:2003 中定義，如下所示。

在 `REFERENCES` 子句中省略列列表意味著外來鍵應參照到被參照表的主鍵。同樣，外來鍵可以定義為 `CREATE TABLE` 語句的一部分。

如果外來鍵是一個單獨列，則可以使用下屬語法:

外來鍵也可以用儲存程序語句定義：

* **child\_table**:
* **parent\_table**: 該候選鍵必須已經定義了
* **col3** 和 **col4**: 外來鍵的名字。包括 1 列至 8 列。

## 參照動作

在對主表做行刪除或修改時，為確保參照完整性，SQL:2003 給出了 5 種「參照動作（**referential actions**）：

* CASCADE
* RESTRICT
* NO ACTION
* SET NULL
* SET DEFAULT

### CASCADE

在對主表的行刪除或修改時，從表中有匹配的外來鍵值的行也相應被刪除或修改。

ON DELETE CASCADE 修改了從表的行為，引入了對從表的自動刪除或修改的行為。

### RESTRICT

在對主表的行刪除或修改時，如果子表中有匹配的外來鍵值的行，則主表中相應的行不能被刪除或修改。

ON DELETE RESTRICT 是對主表的行為約束，雖然寫在了從表的定義中。

RESTRICT 未被 Microsoft SQL Server 2012 及更早的版本支援。

### NO ACTION

NO ACTION 和 RESTRICT 非常像。但 NO ACTION 在嘗試修改主表後檢查參照完整性。如果在這種檢查之前執行了資料庫觸發器，可能在檢查時就不違背參照完整性。

### SET NULL, SET DEFAULT

從表中的外來鍵列被分別設為 NULL 或預設值。

### Triggers

參照動作通常被實現為隱含的觸發器（即通常是隱藏的、具有系統生成名稱的觸發器）。因此，它們受到與使用者定義觸發器相同的限制，並且它們相對於其他觸發器的執行順序可能需要經過考慮；在某些情況下，可能需要將參照操作替換為其等效的使用者定義觸發器，以確保正確的執行順序，或解決變異表 (mutating-table) 的限制。

另一個重要限制出現在事務隔離時：對行的更改可能無法完全級聯，這是因為該行被事務無法「看到」的資料所參照，因此無法級聯。一個例子：當事務嘗試重新編號客戶帳戶時，同時另一事務正在嘗試為同一客戶建立新發票；雖然 CASCADE 規則可能會修改事務可以看到的所有發票行以使其與重新編號的客戶行保持一致，但它不會進入另一個事務來修改那裡的資料；因為資料庫不能保證兩個事務提交時資料一致，所以其中一個事務將被強制回滾（通常是先到先得）。

## 例子

一個簡單的關係：

```
 Supplier (**SupplierNumber**, Name, Address)
 Invoice (**InvoiceNumber**, Text, _SupplierNumber_)
```

資料定義語言語句為：

## 參考文獻

## 外部連結

* 一個詳細介紹外鍵的網站 （頁面存檔備份，存於網際網路檔案館）
* SQL-99 Foreign Keys （頁面存檔備份，存於網際網路檔案館）
* PostgreSQL Foreign Keys （頁面存檔備份，存於網際網路檔案館）
* MySQL Foreign Keys （頁面存檔備份，存於網際網路檔案館）
* FirebirdSQL primary Keys （頁面存檔備份，存於網際網路檔案館）
* SQLite support for Foreign Keys
* Microsoft SQL 2012 table\_constraint (Transact-SQL) （頁面存檔備份，存於網際網路檔案館）