共用方式為


主要鍵和外鍵約束

主索引鍵和外部索引鍵是兩種類型的條件約束,可用以強制執行 SQL Server 資料表中的資料完整性。 這些都是重要的資料庫物件。

本主題包含下列各節。

主鍵條件約束

外鍵條件約束

相關工作

主鍵條件約束

資料表中通常會有一個或多個資料行包含可唯一識別資料表中每個資料列的值。 此資料行稱為資料表的主索引鍵 (PK),強制資料表具有實體完整性。 因為主鍵條件約束可保證唯一的數據,所以通常會在識別數據行上定義它們。

當您為資料表指定主索引鍵條件約束時,資料庫引擎會自動為主索引鍵資料行建立唯一的索引,以強制資料的唯一性。 當主索引鍵用於查詢時,此索引也可讓您快速地存取資料。 如果在多個數據行上定義主鍵條件約束,值可能會在一個數據行內重複,但主鍵條件約束定義中所有數據行的值組合都必須是唯一的。

如下圖所示,Purchasing.ProductVendor 數據表中的 ProductIDVendorID 數據行會形成此數據表的複合主鍵條件約束。 這可確保 ProductVendor 數據表中的每個數據列都有 ProductID 和 VendorID 的唯一組合。 如此可防止插入重複的資料列。

複合主鍵約束

  • 一份資料表只能有一個主索引鍵條件約束。

  • 主鍵不能超過16個數據行,且總索引鍵長度為900個字節。

  • 主鍵條件約束所產生的索引無法導致數據表上的索引數目超過999個非叢集索引和1個叢集索引。

  • 如果針對主鍵約束條件未指定叢集或非叢集,且表上沒有叢集索引,則會使用叢集索引。

  • 主索引鍵條件約束內定義的所有資料行都必須定義為非 Null。 如果未指定可為 Null,則參與主鍵約束的所有欄位都會設為非 Null。

  • 如果在 CLR 使用者定義的類型資料行上定義主索引鍵,類型的實作必須支援二進位排序。

外鍵條件約束

外部索引鍵 (FK) 是可用來建立與強制兩資料表的資料之間連結的一個資料行或資料行組合,以控制外部索引鍵資料表中可儲存的資料。 在外部索引鍵參考中,當存放一個資料表的主索引鍵值的資料行被另一個資料表的資料行參考時,兩資料表之間會建立連結。 此資料行會成為第二個資料表的外部索引鍵。

例如, Sales.SalesOrderHeader 數據表具有 Sales.SalesPerson 數據表的外鍵鏈接,因為銷售訂單與銷售人員之間有邏輯關聯性。 SalesOrderHeader 數據表中的 SalesPersonID 數據行符合 SalesPerson 數據表的主鍵數據行。 SalesOrderHeader 數據表中的 SalesPersonID 數據行是 SalesPerson 數據表的外鍵。 藉由建立這個外鍵關聯性,如果 SalesPersonID 不存在於 SalesPerson 數據表中,就無法將 SalesPersonID 的值插入 SalesOrderHeader 數據表中。

外鍵約束條件的索引

不同於主鍵條件約束,建立外鍵條件約束不會自動建立對應的索引。 不過,基於下列原因,在外部索引鍵上手動建立索引通常很有幫助:

  • 當關聯資料表的資料藉著將資料表的外部索引鍵條件約束和另一個資料表的主要或唯一索引鍵資料行進行比對,而合併於查詢中時,通常會使用外部索引鍵資料行來聯結準則。 索引可讓資料庫引擎在外部索引鍵資料表中快速尋找相關資料。 不過,不需要建立此索引。 即使資料表之間未定義主索引鍵或外部索引鍵條件約束,仍可合併兩個相關資料表的資料,不過兩個資料表之間的外部索引鍵關聯性代表這兩個資料表已經過最佳化,可合併於使用該索引鍵做為準則的查詢中。

  • 系統會檢查主索引鍵條件約束的變更與相關資料表中的外部索引鍵條件約束。

引用完整性

雖然外部索引鍵條件約束的主要用途是控制可儲存在外部索引鍵資料表中的資料,但是它也可控制主索引鍵資料表中資料的變更。 例如,如果銷售人員的數據列從 Sales.SalesPerson 數據表中刪除,而且 Salesperson 的標識符用於 Sales.SalesOrderHeader 數據表中的銷售訂單,則兩個數據表之間的關係完整性會中斷;已刪除的銷售人員銷售訂單會在 SalesOrderHeader 數據表中被遺棄,而不會連結到 SalesPerson 數據表中的數據。

外部索引鍵條件約束可防止這種情況。 如果變更導致外鍵表中的資料連結失效,該約束會透過強制引用完整性來確保不能在主鍵表中對資料進行變更。 如果嘗試刪除主鍵數據表中的數據列或變更主鍵值,則刪除或變更的主鍵值對應至另一個數據表外鍵條件約束中的值時,動作將會失敗。 若要順利變更或刪除外部索引鍵條件約束中的資料列,則必須先刪除外部索引鍵資料表中的外部索引鍵資料,或變更外部索引鍵資料表中的外部索引鍵資料,這樣會將外部索引鍵連結至不同的主索引鍵資料。

連鎖參照完整性

使用串聯式參考完整性條件約束,就可以定義使用者嘗試刪除或更新現有外部索引鍵所指向的索引鍵時,資料庫引擎所採取的動作。 可以定義下列串聯式動作。

NO ACTION 資料庫引擎會引發錯誤,並且會回復父資料表中資料列的刪除或更新動作。

CASCADE 對應的數據列會在父數據表中更新或刪除該數據列時,於參考數據表中更新或刪除。 如果 timestamp 欄位是外鍵或參考鍵中的任一部分,則無法指定 CASCADE。 無法針對具有 INSTEAD OF DELETE 觸發程式的數據表指定 ON DELETE CASCADE。 無法針對具有 INSTEAD OF UPDATE 觸發程式的數據表指定 ON UPDATE CASCADE。

SET NULL 當父數據表中的對應數據列更新或刪除時,組成外鍵的所有值都會設定為 NULL。 若要執行這個條件約束,外部索引鍵資料行必須可為 Null。 無法針對具有 INSTEAD OF UPDATE 觸發程式的資料表進行定義。

SET DEFAULT 如果父數據表中的對應數據列更新或刪除,組成外鍵的所有值都會設定為其預設值。 若要執行這個條件約束,所有外部索引鍵資料行都必須有預設定義。 如果有可為 Null 的資料行,但沒有設定明確的預設值,NULL 便成為這個資料行的隱含預設值。 無法針對具有 INSTEAD OF UPDATE 觸發程式的數據表指定。

您可以在相互具有參考關聯性的資料表上,組合 CASCADE、SET NULL、SET DEFAULT 和 NO ACTION。 如果資料庫引擎發現 NO ACTION,便會停止和回復相關的 CASCADE、SET NULL 和 SET DEFAULT 動作。 當 DELETE 陳述式造成 CASCADE、SET NULL、SET DEFAULT 和 NO ACTION 等動作的組合時,在資料庫引擎檢查任何 NO ACTION 之前,會先套用 CASCADE、SET NULL 及 SET DEFAULT 等動作。

觸發器和級聯引用動作

串聯引用動作會以下列方式引發 AFTER UPDATE 或 AFTER DELETE 觸發程式:

  • 所有直接由原始 DELETE 或 UPDATE 所造成的串聯引用動作都會先執行。

  • 如果在受影響的資料表上定義了任何 AFTER 觸發程式,這些觸發程式會在執行所有串聯動作之後執行。 這些觸發程序的引發順序,將會與串聯式動作相反。 如果單一數據表有多個觸發程式,除非數據表有專用的第一個或最後一個觸發程式,否則會以隨機順序引發。 這個順序是使用 sp_settriggerorder指定。

  • 如果多個串聯鏈結源自為 UPDATE 或 DELETE 動作之直接目標的數據表,則不會指定這些鏈結引發其個別觸發程式的順序。 不過,一定會等到一個鏈結引發完其所有觸發程序後,才引發另外一個鏈結。

  • 無論是否有任何列受到影響,針對 UPDATE 或 DELETE 動作直接目標的數據表上的 AFTER 觸發程式都會觸發。 在此情況下,沒有任何其他資料會受到串聯的影響。

  • 如果上述任一個觸發程式在其他數據表上執行 UPDATE 或 DELETE 作業,這些動作可以啟動次要串聯鏈結。 在所有主要鏈結的觸發程序完成後,會依序處理每個 UPDATE 或 DELETE 作業的次要鏈結。 後續的 UPDATE 或 DELETE 操作可能會重複遞歸此過程。

  • 在觸發器內執行 CREATE、ALTER、DELETE 或其他資料定義語言(DDL)作業可能會導致 DDL 觸發器啟動。 這後續可能會執行啟動其他串聯鏈結和觸發程式的 DELETE 或 UPDATE 作業。

  • 如果在任何特定的級聯引用動作鏈結內產生錯誤,就會引發錯誤,該鏈結中不會引發 AFTER 觸發程式,而且會回復建立鏈結的 DELETE 或 UPDATE 作業。

  • 具有 INSTEAD OF 觸發程序的資料表不能同時具有指定連鎖操作的 REFERENCES 子句。 不過,級聯動作目標數據表上的 AFTER 觸發程式可以在另一個數據表或檢視表上執行 INSERT、UPDATE 或 DELETE 語句,以引發該物件上定義的 INSTEAD OF 觸發程式。

相關工作

下表列出與主鍵和外鍵條件約束相關聯的一般工作。

任務 主題
描述如何建立主鍵。 建立主索引鍵
描述如何刪除主鍵。 刪除主索引鍵
描述如何修改主鍵。 修改主索引鍵
描述如何建立外鍵關聯性 建立外部索引鍵關聯性
描述如何修改外鍵關聯性。 修改外部索引鍵關聯性
描述如何刪除外鍵關聯性。 刪除外部索引鍵關聯性
描述如何檢視外鍵屬性。 檢視外來鍵屬性
描述如何停用複寫的外鍵條件約束。 停用複寫的外部索引鍵條件約束
描述如何在 INSERT 或 UPDATE 語句期間停用外鍵條件約束。 停用 INSERT 和 UPDATE 陳述式的外部索引鍵條件約束