Un altro modo (senza Null e senza cicli nelle FOREIGN KEY
relazioni) è di avere una terza tabella per memorizzare i "figli preferiti". Nella maggior parte dei DBMS, avrai bisogno di un ulteriore UNIQUE
vincolo TableB
.
@Aaron è stato più veloce nell'identificare che la convenzione di denominazione sopra è piuttosto ingombrante e può portare a errori. Di solito è meglio (e ti manterrà sano) se non hai Id
colonne su tutte le tue tabelle e se le colonne (che sono unite) hanno gli stessi nomi nelle molte tabelle che appaiono. Quindi, ecco una ridenominazione:
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)
In SQL Server (che stai utilizzando) hai anche l'opzione della IsFavorite
colonna di bit che menzioni. Il figlio unico preferito per genitore può essere realizzato tramite un indice univoco filtrato:
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 ;
E il motivo principale per cui l'opzione 1 non è consigliata, almeno non in SQL Server, è che il modello di percorsi circolari nei riferimenti a chiave esterna presenta alcuni problemi.
Leggi un articolo piuttosto vecchio: SQL By Design: The Circular Reference
Quando si inseriscono o si eliminano le righe dalle due tabelle, si verificherà il problema "pollo e uovo". Quale tabella devo inserire per prima, senza violare alcun vincolo?
Per risolverlo, devi definire almeno una colonna nullable. (OK, tecnicamente non è necessario, puoi avere tutte le colonne come, NOT NULL
ma solo in DBMS, come Postgres e Oracle, che hanno implementato vincoli differibili. Vedi la risposta di @ Erwin in una domanda simile: Vincolo di chiave esterna complessa in SQLAlchemy su come questo può essere fatto in Postgres). Tuttavia, questa configurazione sembra pattinare sul ghiaccio sottile.
Controlla anche una domanda quasi identica su SO (ma per MySQL) In SQL, è giusto che due tabelle si facciano riferimento? dove la mia risposta è praticamente la stessa. MySQL non ha indici parziali, quindi le uniche opzioni praticabili sono l'FK nullable e la soluzione per tabelle extra.