Nullable Foreign Key Zła praktyka?

114

Załóżmy, że masz tabelę Zamówienia z kluczem obcym do identyfikatora klienta. Teraz załóżmy, że chcesz dodać zamówienie bez identyfikatora klienta (czy to powinno być możliwe, to inna kwestia), musiałbyś ustawić klucz obcy na NULL ... Czy to zła praktyka, czy wolisz pracować z tabelą połączeń między Zamówienia i klienci? Chociaż relacja wynosi od 1 do n, tabela połączeń spowodowałaby, że jest ona od n do n. Z drugiej strony, z tabelą linków, nie mam już tych wartości NULL ...

Tak naprawdę w bazie danych nie będzie zbyt wielu wartości NULL, ponieważ rekord z kluczem obcym do NULL jest tylko tymczasowo, do momentu dodania klienta do zamówienia.

(W moim przypadku nie jest to Zamówienie i Klient).

EDYCJA: A co z nieprzypisanym klientem, do którego można utworzyć łącze?

Lieven Cardoen
źródło
9
JEST to jeden z głównych celów posiadania wartości NULL dostępnych w schemacie bazy danych. Ponadto, dlatego możesz zadeklarować pola NULL lub NOT NULL, aby można było spełnić określone wymagania schematu.
gahooa
7
Początkowo przeczytałem to pytanie jako klucze Nullable Primary i miałem zamiar wejść z jakąś mocną radą ... :-)
Andrzej Doyle

Odpowiedzi:

51

Posiadanie tabeli linków jest prawdopodobnie lepszą opcją. Przynajmniej nie narusza normalizacji BCNF (normalna postać Boyce-Codda). jednakże wolałbym być pragmatycznym. Jeśli masz bardzo mało tych wartości null i są one tylko tymczasowe, myślę, że powinieneś pominąć tabelę linków, ponieważ tylko zwiększa złożoność schematu.

Na marginesie; użycie tabeli połączeń niekoniecznie powoduje, że jest to n do n, jeśli w tabeli połączeń używasz klucza obcego wskazującego na tabelę zamówień jako klucza podstawowego w tej tabeli połączeń, relacja nadal wynosi 1..n. W tej tabeli łączy może znajdować się tylko jeden wpis na zamówienie.

Patrik Hägne
źródło
2
source__destination_link lub SourceDestination
Svisstack
7
Chciałbym usłyszeć o sytuacji, w której posiadanie tablicy linków jest lepsze, nigdy nie spotkałem się z sytuacją, w której poprawiłoby to w jakikolwiek sposób przepływ procesów.
Reimius
5
Jak wskazałem w mojej odpowiedzi, byłbym pragmatyczny w tym konkretnym przypadku i nie używałbym tabeli linków. Jestem pewien, że zwykłe formularze nie zostały wynalezione w celu usprawnienia przebiegu procesu, ale raczej w celu zapewnienia spójności i uniknięcia nadmiarowości. Jest to jednak bardzo ogólna dyskusja, myślę, że należy ją rozpatrywać indywidualnie.
Patrik Hägne
110

Nie Nie ma nic złego w zerowych ZK. Jest to częste, gdy jednostka, na którą wskazuje FK, jest w relacji (zero lub jeden) do (1 lub wiele) z podstawową tabelą, do której odwołuje się klucz.

Przykładem może być sytuacja, w której w tabeli znajdował się zarówno adres fizyczny, jak i atrybut (kolumna) adresu pocztowego, z elementami FK do tabeli adresów. Możesz ustawić wartość zerową adresu fizycznego do obsługi, gdy jednostka ma tylko skrytkę pocztową (adres pocztowy), a adres pocztowy może być obsługiwany, gdy adres pocztowy jest taki sam jak adres fizyczny (lub nie).

Charles Bretana
źródło
39

Kolumny dopuszczające wartość null mogą znajdować się w przedziałach od 1NF do 5NF, ale nie w 6NF, zgodnie z tym, co przeczytałem.

Tylko wtedy, gdy wiesz lepiej niż Chris Date "co naprawdę oznacza pierwsza normalna forma". Jeśli x i y są dopuszczalne wartości null, a rzeczywiście w pewnym wierszu x i y są oba null, to WHERE x=ynie daje true. Dowodzi to ponad wszelką wątpliwość, że null nie jest wartością (ponieważ każda rzeczywista wartość jest zawsze sobie równa). A ponieważ RM nakazuje, że „musi istnieć wartość w każdej komórce tabeli”, każda rzecz, która prawdopodobnie zawiera wartości null, nie jest rzeczą relacyjną, a zatem kwestia 1NF nawet się nie pojawia.

Słyszałem, jak argumentował, że kolumny dopuszczające wartość zerową generalnie przerywają pierwszy stopień normalizacji.

Zobacz powyżej rozsądny powód leżący u podstaw tego argumentu.

Ale w praktyce jest to bardzo praktyczne.

Tylko jeśli jesteś odporny na bóle głowy, które zwykle powoduje w całej reszcie świata. Jednym z takich problemów (i to tylko nieznacznym, w porównaniu do innych nullzjawisk) jest fakt, że WHERE x=yw SQL faktycznie oznacza WHERE x is not null and y is not null and x=y, ale większość programistów po prostu nie jest tego świadoma i po prostu czyta. Czasami bez szkody, innym razem nie.

W rzeczywistości kolumny dopuszczające wartość null naruszają jedną z najbardziej fundamentalnych zasad projektowania baz danych: nie łącz różnych elementów informacji w jednej kolumnie. Wartości null robią dokładnie to, ponieważ łączą wartość logiczną „to pole jest / nie jest naprawdę obecne” z wartością rzeczywistą.

Erwin Smout
źródło
18
+1 dla „GDZIE x nie jest zerowe, a y nie jest zerowe i x = y”. Nie był tego świadomy.
RobM
1
Bardzo ładnie przedstawione argumenty i przykłady.
pedz
1
Jeden problem. Gdy wartość „nie istnieje” (co jest scenariuszem w świecie rzeczywistym), a atrybut bazy danych nie zezwala na wartości null, każda wartość atrybutu jest ZŁA. Jeśli chodzi o bóle głowy, pamiętaj, KISS, nie oznacza to tylko prostoty, to znaczy Utrzymuj to tak prosto, jak to możliwe, ale nie prostsze. Jeśli „model relacyjny” wymaga nierealistycznego, głupiego wyniku, to być może reguły muszą zostać rozszerzone, aby poradzić sobie z niezbędnymi danymi ze świata rzeczywistego?
Charles Bretana
1
Wykazano, że logika trójwartościowa prowadzi do potrzeby logiki czterowartościowej, a to prowadzi do potrzeby logiki pięciowartościowej itp. Itd. Logika dwuwartościowa jest wystarczająca, ale struktury danych otrzymujemy, gdy jego zastosowanie sprawia, że ​​„tak proste, jak to tylko możliwe”, jest nadal znacznie mniej proste niż „tak proste, jak byśmy chcieli”.
Erwin Smout
2
Chris Date, Logika i bazy danych, rozdz. 6, „Dlaczego logika relacyjnego DBMS nie może być wielowartościowa”, str. 145. Lista odniesień do tego rozdziału również powinna być interesująca, zwłaszcza te dotyczące McGoverana.
Erwin Smout
13

Nie widzę nic złego w tym, że jest to tylko opcjonalna relacja n-1, która będzie reprezentowana przez wartość null w kluczu obcym. W przeciwnym razie, jeśli umieścisz tabelę linków, będziesz musiał zarządzać tym, że nie stanie się ona relacją nn, co spowoduje jeszcze więcej problemów.

pedromarce
źródło
2
W rzeczywistości jest to relacja 0-N, a nie opcjonalna relacja 1-N. Ale ja się z tobą zgadzam.
Eric J.
5
Zarządzać? To proste UNIKALNE ograniczenie po stronie 0 do 1!
wqw
2
Tak, jest to UNIKALNE ograniczenie, ale będziesz musiał również poradzić sobie z możliwymi wyjątkami później w swoim kodzie z powodu tego ograniczenia ...
pedromarce
4

Relacje opcjonalne są zdecydowanie możliwe w modelu relacyjnym.

Możesz użyć wartości null, aby wyrazić brak relacji. Są wygodne, ale spowodują te same bóle głowy, które null powodują gdzie indziej. Jednym miejscem, w którym nie powodują żadnych problemów, jest dołączanie. Wiersze, które mają wartość null w kluczu obcym, nie pasują do żadnych wierszy w tabeli, do której się odwołuje. Więc wypadają z połączenia wewnętrznego. Jeśli wykonujesz łączenia zewnętrzne, i tak będziesz mieć do czynienia z wartościami zerowymi.

Jeśli naprawdę chcesz uniknąć wartości null (szósta normalna forma), możesz zdekomponować tabelę. Jedna z dwóch zdekomponowanych tabel zawiera dwie kolumny kluczy obcych. Jeden to opcjonalny klucz obcy, który posiadasz, a drugi to klucz obcy odwołujący się do klucza podstawowego oryginalnej tabeli. Teraz musisz użyć ograniczeń, aby zapobiec przekształceniu się relacji wiele-do-wielu, jeśli chcesz temu zapobiec.

Walter Mitty
źródło
2

Użycie wartości NULL byłoby dobrym sposobem na wyczyszczenie niekompletnych zamówień:

SELECT * FROM `orders`
WHERE `started_time` < (UNIX_TIMESTAMP() + 900) AND `customer_id` IS NULL

Powyższe pokaże zamówienia starsze niż 15 minut bez powiązanego identyfikatora klienta.

matpie
źródło
1

Jeśli dodajesz zamówienie tylko tymczasowo bez identyfikatora klienta do momentu zdefiniowania klienta, czy nie byłoby łatwiej dodać klienta i zamówienie w jednej transakcji, eliminując w ten sposób potrzebę wprowadzania klucza obcego NULL i unikając wszelkich ograniczeń lub wyzwalaczy ustawiłeś, że jesteś gwałcony?

Zwykle taka sytuacja ma miejsce w aplikacjach internetowych, w których zamówienie jest szczegółowo opisane, zanim klient określi, kim jest. W takich sytuacjach zamówienie jest utrzymywane w stanie serwera lub w pliku cookie do momentu dostarczenia całego stanu niezbędnego do pełnego zamówienia, w którym to momencie zamówienie jest utrwalane w bazie danych.

NULL klucze obce są w porządku dla rzeczy takich jak adresy, jak wspomniano powyżej. Ale pole klienta o wartości NULL nie ma sensu dla zamówienia i powinno być ograniczone.

Mark Green
źródło
Przykładem był klient zamówienia. W mojej aplikacji jest to bardziej podobne do adresów. Nie można od razu znaleźć przykładu, który byłby poprawny. dzięki.
Lieven Cardoen
1
Może to być prawidłowy scenariusz, jeśli baza danych była używana do przechowywania pozycji w koszyku, w którym koszyk nie należy do zarejestrowanego użytkownika.
Johnie Karr
1

Zawsze możesz dodać sztuczny wiersz do tabeli Customer, na przykład Id = -1 i CustomerName = 'Unknown', a następnie w przypadkach, gdy normalnie ustawisz CustomerId w Order NULL, ustaw go na -1.

Pozwala to na brak zerowych elementów FK, ale nadal odpowiednio reprezentuje brak danych (i uchroni Cię przed dalszymi użytkownikami, którzy nie wiedzą, jak radzić sobie z wartościami NULL).

Stephen S.
źródło
Aby to dodać, pamiętaj, że wartości NULLS nie są zapisywane w indeksie (w Oracle), więc oznacza to, że pominięcie tabeli linków i wybranie wartości zerowej FK miałoby sens - z punktu widzenia wydajności. Inną rzeczą, na której może polegać, jest to, czy chcesz zapisać cokolwiek innego w tej tabeli łączy, na przykład KTO utworzył łącze i kiedy? Czy link jest teraz nieaktywny / usunięty (ale kiedyś był?)
Worthy7
To jest zły pomysł. Jeśli masz ustawiony klucz obcy, a dane, na które wskazuje, zostaną później usunięte, nie otrzymasz wyjątku klucza obcego, a teraz Twoje dane są bezsensowne. Gorzej, jeśli coś innego zostanie później przypisane do tego klucza,
wskażesz
0

Zerowalne elementy FK dla opcjonalnych relacji wiele do jednego są całkowicie w porządku.

Henning
źródło
-1

Słyszałem, jak argumentowano, że kolumny z wartością zerową generalnie przerywają pierwszy stopień normalizacji. Ale w praktyce jest to bardzo praktyczne.

Bryan McLemore
źródło
3
Kolumny dopuszczające wartość null mogą znajdować się w przedziałach od 1NF do 5NF, ale nie w 6NF, zgodnie z tym, co przeczytałem.
Walter Mitty
-1

Tak, coś jest nie tak. Nie jest to klucz obcy, jeśli dopuszcza wartość null. Projekt bazy danych według kodu. Może utworzysz zerowy link do nieprzypisanych. lub „Nieprzypisane”, jeśli używasz znaku kol. Zachowaj 100% integralność danych.

danny117
źródło