Mam tabelę, w której wiersze mogą być ze sobą powiązane, i logicznie związek przebiega w obie strony (w zasadzie jest bezkierunkowy) między dwoma rzędami. (A jeśli zastanawiasz się, tak, to naprawdę powinien to być jeden stół. Są to dwie rzeczy dokładnie tego samego logicznego bytu / typu). Mogę wymyślić kilka sposobów na przedstawienie tego:
- Przechowuj relację i jej odwrotność
- Przechowuj relację w jeden sposób, ogranicz przechowywanie bazy danych w inny sposób i miej dwa indeksy o przeciwnych zamówieniach dla FK (jeden indeks to indeks PK)
- Zapisz relację w jedną stronę za pomocą dwóch indeksów i pozwól, by i tak wstawić drugą (brzmi trochę pechowo, ale hej, kompletność)
- Utwórz jakiś stół grupujący i umieść na nim FK na oryginalnym stole. (Podnosi mnóstwo pytań. Tabela grupowania miałaby tylko liczbę; dlaczego w ogóle miałaby tabelę? Uczynić FK NULLable lub mieć grupy z jednym wierszem powiązane?)
Jakie są główne zalety i wady tych sposobów i oczywiście jest jakiś sposób, o którym nie myślałem?
Oto SQLFiddle do zabawy: http://sqlfiddle.com/#!12/7ee1a/1/0 . (Zdarza się, że jest PostgreSQL, ponieważ tego właśnie używam, ale nie sądzę, że to pytanie jest bardzo specyficzne dla PostgreSQL.) Obecnie przechowuje zarówno relację, jak i jej odwrotność, jako przykład.
database-design
foreign-key
jpmc26
źródło
źródło
Odpowiedzi:
To, co zaprojektowałeś, jest dobre. To, co należy dodać, to ograniczenie uniemożliwiające ukierunkowanie związku. Nie możesz więc mieć
(1,5)
wiersza bez(5,1)
dodanego wiersza.Można to osiągnąć * za pomocą ograniczenia do odwoływania się do tabeli mostu.
*: można tego dokonać w Postgres, Oracle, DB2 i wszystkich DBMS, które zaimplementowały ograniczenia klucza obcego zgodnie z opisem standardu SQL (odroczone, np. sprawdzone na końcu transakcji). Odroczone sprawdzanie i tak nie jest tak naprawdę potrzebne, jak w SQL- Serwer, który sprawdza je na końcu instrukcji i ta konstrukcja nadal działa. Nie możesz tego zrobić w MySQL, ponieważ „InnoDB sprawdza rzędy po rzędzie UNIQUE i OBCYCH KLUCZOWYCH ograniczeń” .
Tak więc w Postgres następujące wymagania będą pasować do twoich wymagań:
Testowany w: SQL-Fiddle
Jeśli spróbujesz dodać wiersz
(1,5)
:Nie działa z:
Dodatkowo możesz dodać
CHECK
ograniczenie, jeśli chcesz zabronić(y,y)
wierszy:Istnieją inne sposoby realizacji tego, jak wspomniałeś, na przykład przechowywanie tylko jednego kierunku relacji (w jednym wierszu, a nie dwóch) przez wymuszenie niższego identyfikatora
x_id1
i wyższego identyfikatora wx_id2
kolumnie. Wygląda na łatwiejsze do wdrożenia, ale zwykle prowadzi do bardziej złożonych zapytań później:źródło