Innym sposobem (bez wartości zerowych i bez cykli w FOREIGN KEY
relacjach) jest posiadanie trzeciego stołu do przechowywania „ulubionych dzieci”. W większości DBMS potrzebujesz dodatkowego UNIQUE
ograniczenia TableB
.
@Aaron szybciej zidentyfikował, że powyższa konwencja nazewnictwa jest raczej uciążliwa i może prowadzić do błędów. Zazwyczaj jest to lepsze (i zapewni ci rozsądek), jeśli nie masz Id
kolumn we wszystkich tabelach i jeśli kolumny (które są połączone) mają takie same nazwy w wielu pojawiających się tabelach. Oto zmiana nazwy:
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)
W SQL-Server (którego używasz) masz również opcję wspomnianej IsFavorite
kolumny bitów. Unikalne ulubione dziecko na rodzica można osiągnąć poprzez filtrowany Unikalny Indeks:
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 ;
A głównym powodem, dla którego twoja opcja 1 nie jest zalecana, przynajmniej nie w SQL Server, jest to, że wzór ścieżek kołowych w odniesieniach do klucza obcego ma pewne problemy.
Przeczytaj dość stary artykuł: SQL By Design: The Circular Reference
Podczas wstawiania lub usuwania wierszy z dwóch tabel napotkasz problem „kurczaka i jajka”. Którą tabelę powinienem wstawić jako pierwszy - bez naruszania jakichkolwiek ograniczeń?
Aby rozwiązać ten problem, musisz zdefiniować co najmniej jedną kolumnę nullable. (OK, technicznie nie masz, możesz mieć wszystkie kolumny tak NOT NULL
, ale tylko w DBMS, takich jak PostgreSQL i Oracle, które zostały wdrożone odroczeniu ograniczenia Zobacz @ odpowiedź Erwin w podobnym pytaniem. Kompleks ograniczenie klucz obcy w SQLAlchemy , w jaki sposób można to zrobić w Postgres). Mimo to ta konfiguracja przypomina jazdę na cienkim lodzie.
Sprawdź także prawie identyczne pytanie w SO (ale dla MySQL). W SQL, czy dwie tabele mogą się odnosić? gdzie moja odpowiedź jest prawie taka sama. MySQL nie ma jednak częściowych indeksów, więc jedynymi realnymi opcjami są zerowalne FK i dodatkowe rozwiązanie tabeli.