2011-09-27 85 views
174

請爲我澄清兩件事:外鍵是否可以是NULL和/或重複的?

  1. 外鍵是否可以爲NULL?
  2. 外鍵可以重複嗎?

的公平性,我知道,NULL不應外鍵使用,但在我的一些應用程序,我能夠在Oracle和SQL Server的輸入NULL,我不知道爲什麼。

+1

@Adrian:最好的我的知識外鍵不能爲空,但它是在SQL服務器和甲骨文空。你能解釋爲什麼嗎? – jams

+0

@Jams - 閱讀我答案中的鏈接。 – JNK

+7

這不能被刪除,因爲答案和問題很有用。隨意編輯問題以改進它。 –

回答

315

簡短的回答:是的,它可以是NULL或複製。

我想解釋爲什麼外鍵可能需要爲空或可能需要唯一或不唯一。首先記住一個外鍵只需要該字段中的值必須首先存在於不同的表(父表)中。這就是所有FK的定義。根據定義,空值不是一個值。空意味着我們還不知道價值是什麼。

讓我給你一個真實的例子。假設您有一個存儲銷售建議的數據庫。進一步假設每個提案只有一個銷售人員和一個客戶。所以你的提案表會有兩個外鍵,一個是客戶ID,另一個是銷售代表ID。但是,在創建記錄時,銷售代表並不總是被分配(因爲沒有人可以自由處理它),所以客戶ID被填寫,但銷售代表ID可能爲空。換句話說,通常你需要能夠在輸入數據時不知道它的值的情況下擁有一個空FK,但你知道表中需要輸入的其他值。要允許FK中的空值,通常你只需要在具有FK的字段上允許空值。空值與作爲FK的想法是分開的。

它是唯一的還是不唯一涉及到表是否與父表具有一對一或多對多的關係。現在,如果你有一對一的關係,你可能會把所有的數據放在一張表中,但是如果表太寬或者數據是在另一個主題上(僱員保險示例@tbone給出了例如),那麼你需要單獨的表格與FK。然後你會想讓這個FK或者PK(保證唯一性)或者對它進行獨特的約束。

大多數FK是一對多的關係,這就是你從FK得到的,而沒有對該領域增加進一步的限制。所以你有一個訂單表和訂單明細表。如果客戶一次訂購十件商品,則他有一個訂單和十個訂單明細記錄,其中包含與FK相同的訂單ID。

+9

因此,這樣做的目的是要比名爲「未分配」的假銷售人員更好? –

+4

評論。空值在不知道SQL(錯誤)如何處理3VL的人的查詢中留下很多空間。如果銷售人員確實不需要特定的R表,那麼您不包括該記錄。單獨的表格可以是「ProposalAssignedTo」或其他適當的約束。然後,查詢作者可以加入到該表中,併爲提案沒有銷售人員時想要執行的操作提供自己的邏輯。 NULL不僅僅意味着「我們不知道」 - 它可以用於很多事情(這就是爲什麼它幾乎總是一個壞主意) –

+9

@nWest,我不允許無能的人查詢我的數據庫任何不懂如何處理空值的開發者都是無能的。在特定字段的初始數據輸入時,有時候數據未知,但當時需要其他字段。 – HLGEM

32

從馬的嘴:

外鍵允許均爲空,即使沒有 匹配的主鍵或惟一鍵

外鍵

沒有約束鍵值

當外鍵上沒有定義其他約束時,子表中任何行號的 都可以引用相同的父鍵值。 該模型允許在外鍵中使用空值。 ...

上NOT NULL約束外鍵

當空不在 不允許外鍵,子表中的每一行都必須明確父鍵引用 值,因爲空值不允許在國外 的關鍵。

子表中的任意行數都可以引用同一父鍵 的鍵值,因此此模型在父鍵和外鍵之間建立了一對多關係 。但是,子表 中的每一行都必須具有對父鍵值的引用;在外鍵中不存在 值(空)是不允許的。前面的部分可以用 中的同一個例子來說明這種關係。 但是,在這種情況下,員工必須參考具體的 部門。

唯一約束外鍵

當UNIQUE約束外鍵定義 ,子表中可以 參考給定父鍵值只有一行。該模型允許 外鍵中的空值。

該模型建立了父代 與外鍵之間的一對一關係,該外鍵允許 外鍵中的未定值(空值)。例如,假設員工表中有一個名爲MEMBERNO的列 ,指的是 公司保險計劃中的員工會員編號。此外,名爲INSURANCE的表具有名爲MEMBERNO的主鍵 ,表中的其他列分別保留有關員工保險單的 信息。該MEMBERNO在 僱員表必須是一個外鍵和一個唯一的密鑰:

  • 要執行EMP_TAB和 保險表(外鍵約束)

  • 保證之間的引用完整性規則每個員工都有一個唯一的會員號碼(在 唯一鍵約束)

UNIQUE和NOT NULL約束S於外鍵

當既獨特 和NOT NULL約束外鍵定義,在子表中只有一行 可以參考給定父鍵值,因爲 NULL值中不允許外鍵,子表 表中的每一行都必須顯式引用父鍵中的值。

看到這個:

Oracle 11g link

1

下面是使用Oracle語法的例子:
首先,讓我們創建一個表COUNTRY

CREATE TABLE TBL_COUNTRY (COUNTRY_ID VARCHAR2 (50) NOT NULL) ; 
ALTER TABLE TBL_COUNTRY ADD CONSTRAINT COUNTRY_PK PRIMARY KEY (COUNTRY_ID) ; 

創建表省

CREATE TABLE TBL_PROVINCE(
PROVINCE_ID VARCHAR2 (50) NOT NULL , 
COUNTRY_ID VARCHAR2 (50) 
); 
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_PK PRIMARY KEY (PROVINCE_ID) ; 
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_COUNTRY_FK FOREIGN KEY (COUNTRY_ID) REFERENCES TBL_COUNTRY (COUNTRY_ID) ; 

這將運行完全正常的甲骨文。注意第二個表中的COUNTRY_ID外鍵沒有「NOT NULL」。

現在要在PROVINCE表中插入一行,只需指定PROVINCE_ID即可。但是,如果您還選擇指定COUNTRY_ID,則它必須已存在於COUNTRY表中。

-4

我認爲一個表的外鍵也是其他表的外鍵,所以它不會允許null。所以在外鍵中沒有空值的問題。

8

是的高級程序員可以爲空的外鍵......我會添加另一個場景,其中外鍵需要爲空...... 假設我們在應用程序中有表格評論,圖片和視頻允許對圖片和視頻進行評論。在評論表中,我們可以有兩個外鍵PicturesId和VideosId以及主鍵CommentId。因此,當您對視頻發表評論時,只需要VideosId,pictureId將爲null ...,如果您對某張圖片發表評論,則只需PictureId,而VideosId將爲null ...

+1

我認爲有更好的方法來解決這個問題。您可以創建兩列,即「id」和「type」,它將包含外鍵表的ID和名稱,而不是創建新列。例如,id = 1,type =圖片將代表帶有id 1的圖片表的鏈接。使用此解決方案的優點是,當將註釋添加到其他表格時,您不必創建新列。缺點是在db級別沒有外鍵約束,相反,約束必須是應用程序級別。 – Agent47DarkSoul

+1

@Agent:我們在生產中使用了這個「解決方案」。不要這樣做,這很糟糕。使查詢成爲這樣一團糟,「如果它是類型1,加入這張表,否則加入到這個」。這對我們來說是一場噩夢。我們最終做了這個答案,併爲每種類型的連接創建了一個新列。創建列很便宜。蟾蜍幾乎只有瑕疵,很多列讓蟾蜍難以使用,但這只是蟾蜍的一個缺陷。 – user128216

+1

@FighterJet Rails提供了一個很棒的ORM框架,它可以處理這個解決方案的複雜查詢。 – Agent47DarkSoul

0

簡而言之,識別「實體之間的關係是ER-Model的一部分,並且在設計ER-Diagram時可在Microsoft Visio中使用。這是在「零或大於零」或「零或一」類型的實體之間強制實施基數所必需的。注意基數中的「零」而不是「一對多」中的「一」。

現在,基數可能爲「零」(非識別)的非識別關係的示例是當我們在一個實體中說出記錄/對象時 - 「可能」或「可能不」具有作爲參考另一個實體-B中的記錄。

由於實體-A的一條記錄有可能將自己標識爲其他實體-B的記錄,因此在實體-B中應該有一列具有實體記錄的標識值-B。如果實體-A中沒有記錄識別實體-B中的記錄(或者對象),那麼該列可以是「空」。在面向對象(真實世界)範式中,有些情況下,類B的對象不一定依賴於(強耦合)類A的對象,因爲它的存在,這意味着類B是鬆散的,與A類相聯繫,使得A類可以「包含」(包含)A類的對象,而不是B類的對象的概念必須具有(構成)A類的對象,因爲其( B類對象)創作。

從SQL查詢的角度來看,您可以查詢實體-B中所有記錄爲「非空」的實體-B保留的外鍵。這將爲實體-A中的行帶來具有特定相應值的所有記錄,或者,具有空值的所有記錄將是在實體-B中的實體-A中沒有任何記錄的記錄。

0

默認情況下,外鍵沒有限制,外鍵可以爲空且重複。

在創建表/更改表時,如果添加了任何唯一性限制或不爲空,那麼只有它不允許空值/重複值。

-1

我認爲考慮表中可能的基數更好。 我們可以有可能的最小基數零。如果它是可選的,那麼來自相關表的元組的最小參與可以爲零,現在你面臨允許外鍵值被允許爲null的必要性。

但是答案是全部取決於業務。