Sql-Server

如何與有特權的孩子建立一對多的關係?

  • January 15, 2018

我想要一個一對多的關係,對於每個父母,一個或零個孩子被標記為“最喜歡的”。然而,並不是每個父母都會有孩子。(將父母視為此站點上的問題,將孩子視為答案,將收藏視為已接受的答案。)例如,

TableA
   Id            INT PRIMARY KEY

TableB
   Id            INT PRIMARY KEY
   Parent        INT NOT NULL FOREIGN KEY REFERENCES TableA.Id

按照我的看法,我可以在 TableA 中添加以下列:

   FavoriteChild INT NULL FOREIGN KEY REFERENCES TableB.Id

或表B的以下列:

   IsFavorite    BIT NOT NULL

第一種方法的問題在於它引入了一個可以為空的外鍵,據我所知,它不是規範化的形式。第二種方法的問題是需要做更多的工作來確保最多一個孩子是最喜歡的。

我應該使用什麼樣的標準來確定使用哪種方法?或者,還有其他我沒有考慮的方法嗎?

我正在使用 SQL Server 2012。

另一種方法(沒有 Null 並且FOREIGN KEY關係中沒有循環)是有第三個表來儲存“最喜歡的孩子”。在大多數 DBMS 中,您需要UNIQUETableB.

@Aaron 更快地發現上面的命名約定相當繁瑣並且可能導致錯誤。Id如果您的表中沒有列並且列(連接的)在出現的許多表中具有相同的名稱,通常會更好(並且會讓您保持理智) 。所以,這裡是一個重命名:

Parent
   ParentID        INT NOT NULL PRIMARY KEY

Child
   ChildID         INT NOT NULL PRIMARY KEY
   ParentID        INT NOT NULL FOREIGN KEY REFERENCES Parent (ParentID)
   UNIQUE (ParentID, ChildID)

FavoriteChild
   ParentID        INT NOT NULL PRIMARY KEY
   ChildID         INT NOT NULL 
   FOREIGN KEY (ParentID, ChildID) 
       REFERENCES Child (ParentID, ChildID)

在 SQL-Server(您正在使用的)中,您還可以選擇IsFavorite您提到的位列。每個父母唯一最喜歡的孩子可以通過過濾的唯一索引來完成:

Parent
   ParentID        INT NOT NULL PRIMARY KEY

Child
   ChildID         INT NOT NULL PRIMARY KEY
   ParentID        INT NOT NULL FOREIGN KEY REFERENCES Parent (ParentID)
   IsFavorite      BIT NOT NULL

CREATE UNIQUE INDEX is_FavoriteChild
 ON Child (ParentID)
 WHERE IsFavorite = 1 ;

不推薦您的選項 1,至少在 SQL-Server 中不推薦的主要原因是外鍵引用中的循環路徑模式存在一些問題。

閱讀一篇相當古老的文章:SQL By Design: The Circular Reference

從兩個表中插入或刪除行時,您將遇到“雞和蛋”問題。我應該先插入哪個表 - 不違反任何約束?

為了解決這個問題,您必須定義至少一列可為空。(好的,從技術上講,您不必這樣做,NOT NULL但只能在 DBMS 中使用所有列,例如 Postgres 和 Oracle,它們已經實現了可延遲約束。請參閱@Erwin 在類似問題中的回答:**SQLAlchemy 中的複雜外鍵約束**如何這可以在 Postgres 中完成)。儘管如此,這種設置感覺就像在薄冰上滑冰。

還要檢查一個幾乎相同的問題 SO(但對於 MySQL)**在 SQL 中,兩個表可以相互引用嗎?**我的答案幾乎相同。MySQL 沒有部分索引,因此唯一可行的選項是可為空的 FK 和額外表解決方案。

引用自:https://dba.stackexchange.com/questions/34151