2010-04-11 84 views
8

我對FOREIGN KEY和CHECK約束之間的區別感到困惑 - 他們似乎達到了相同的結果。檢查和外鍵有什麼區別?

我的意思是我可以創建一個表並在另一個表上強制執行一個外鍵,但是我可以創建一個CHECK來確保另一個表中的值。

有什麼區別以及何時使用這個或那個?

回答

6

一個外鍵約束確保項不存在

編輯 另一個表

按照正確的註釋存在於另一個表...或相同的表。 - Mark Byers

CHECK約束確保條目遵循一些規則。

CHECK Constraints

CHECK約束通過限制由列接受的值執行域的完整性。它們與FOREIGN KEY約束類似,它們控制放在列中的值。 區別在於它們如何確定哪些值是有效的:FOREIGN KEY約束從另一個表中獲取有效值的列表,並且CHECK約束根據不基於另一列中的數據的邏輯表達式確定有效值。

+4

存在於另一張桌子......或同一張桌子上。 – 2010-04-11 17:29:19

+0

CHECK約束確定不基於另一列中的數據的...。 不太正確,檢查約束可以包含多列(至少10g)。更好的是說「不是基於另一個表中的數據」。 – Juraj 2010-04-19 20:43:38

2

外鍵約束比CHECK約束更強大。
外鍵約束意味着列(在當前表中)只能具有已存在於外表列中的值(可能包括相同的表,通常是爲分層數據完成的)。這意味着隨着值列表的變化 - 變大或變小 - 不需要更新約束。

檢查約束不能引用當前表之外的任何列,也不能包含子查詢。通常,這些值是硬編碼的,如BETWEEN 100 and 999IN (1, 2, 3)。這意味着隨着情況的變化,您必須每次更新CHECK約束。此外,外鍵關係在實體關係圖(ERD)上可見,而CHECK約束永遠不會。好處是有人可以讀取ERD並從中構建查詢,而無需使用大量的DESC表命令來知道哪些列是哪裏以及哪些與構建適當的連接有關。

最佳做法是首先使用外鍵(和支持表)。使用CHECK約束作爲不能使用外鍵的情況的備份,而不是驗證數據的主要解決方案。

+2

外鍵不必是單列鍵。 – 2010-04-11 18:04:04

1

它取決於您的DBMS(您沒有指定),但從某種意義上說,您是正確的:外鍵約束是檢查約束的特定情況。有數據庫管理系統不允許你制定一個外鍵約束作爲檢查約束。

檢查約束的主要目的是描述適用於表中單個行的條件。例如,我有一張元素表(如氫,氦,...),並且元素的符號被限制爲以大寫字母開頭,並且後面跟着零個,一個或兩個小寫字母(兩個小寫字母,但尚未被發現但預測的元素:Uus - ununseptium(117) ,它剛剛被隔離但尚未命名)。這可以是一個CHECK約束的主題:

CHECK(Symbol MATCHES "[A-Z][a-z]{0,2}") 

假設MATCHES存在並支持適當的正則表達式語言。

你也可以有一個比較值的檢查約束:

CHECK(OrderDate <= ShipDate OR ShipDate IS NULL) 

爲了表達一個外鍵約束的檢查約束,你要允許CHECK子句中執行查詢。假設:

CHECK(EXISTS(SELECT * FROM SomeTable AS s 
       WHERE ThisTable.pk_col1 = s.pk_col1 AND 
        ThisTable.pk_col2 = s.pk_col2)) 

此示例顯示了一些問題。我沒有一個方便的表格別名,用於編寫檢查約束的表格 - 我認爲它是'ThisTable'。構造是冗長的。假設在SomeTable主鍵的列pk_col1pk_col2聲明,那麼外鍵子句是更加緊湊:

FOREIGN KEY (pk_col1, pk_col2) REFERENCES SomeTable 

或者,如果你引用一個替代鍵,而不是主鍵:

FOREIGN KEY (pk_col1, pk_col2) REFERENCES SomeTable(ak_col1, ak_col2) 

這在命名上更加緊湊 - 因此出錯的可能性更小 - 並且可以由服務器進行特殊配置,因爲特殊符號意味着它知道它正在處理外鍵約束,而通用檢查子句必須仔細檢查,看它是否符合許多可能的形式之一相當於外鍵。

問題問:何時使用檢查約束以及何時使用外鍵約束?

  • 使用CHECK約束來指定可在單個行中檢查的條件。
  • 使用FOREIGN KEY約束來指定當前行中的值必須與某個表的某個其他唯一鍵(候選鍵,通常是主鍵而非備選鍵)中的行的值匹配 - 這可能會成爲同一張桌子或(更一般地)不同的桌子。