Une autre façon (sans Nulls et sans cycles dans les FOREIGN KEY
relations) est d'avoir une troisième table pour stocker les "enfants préférés". Dans la plupart des SGBD, vous aurez besoin d'une UNIQUE
contrainte supplémentaire TableB
.
@Aaron a été plus rapide à identifier que la convention de dénomination ci-dessus est plutôt lourde et peut entraîner des erreurs. Il est généralement préférable (et vous gardera sain d'esprit) si vous n'avez pas de Id
colonnes partout dans vos tables et si les colonnes (qui sont jointes) ont les mêmes noms dans les nombreuses tables qui apparaissent. Alors, voici un changement de nom:
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)
Dans SQL-Server (que vous utilisez), vous avez également la possibilité de la IsFavorite
colonne de bits que vous mentionnez. L'enfant préféré unique par parent peut être accompli via un index unique filtré:
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 ;
Et la principale raison pour laquelle votre option 1 n'est pas recommandée, du moins pas dans SQL-Server, est que le modèle de chemins circulaires dans les références de clé étrangère a quelques problèmes.
Lire un article assez ancien: SQL By Design: la référence circulaire
Lorsque vous insérez ou supprimez des lignes des deux tableaux, vous rencontrerez le problème "poulet et œuf". Quelle table dois-je insérer en premier - sans violer aucune contrainte?
Pour résoudre ce problème, vous devez définir au moins une colonne nullable. (OK, techniquement, vous n'êtes pas obligé, vous pouvez avoir toutes les colonnes, NOT NULL
mais uniquement dans les SGBD, comme Postgres et Oracle, qui ont implémenté des contraintes reportables. Voir la réponse de @ Erwin dans une question similaire: Contrainte de clé étrangère complexe dans SQLAlchemy sur la façon dont cela peut être fait dans Postgres). Pourtant, cette configuration ressemble à du patinage sur de la glace mince.
Vérifiez également une question presque identique à SO (mais pour MySQL) En SQL, est-il correct que deux tables se réfèrent l'une à l'autre? où ma réponse est à peu près la même. MySQL n'a cependant pas d'index partiel, donc les seules options viables sont le FK nullable et la solution de table supplémentaire.