Mam tabelę podobną do następującej:
create table my_table (
id int8 not null,
id_A int8 not null,
id_B int8 not null,
id_C int8 null,
constraint pk_my_table primary key (id),
constraint u_constrainte unique (id_A, id_B, id_C)
);
I chcę (id_A, id_B, id_C)
się wyróżniać w każdej sytuacji. Tak więc następujące dwie wstawki muszą powodować błąd:
INSERT INTO my_table VALUES (1, 1, 2, NULL);
INSERT INTO my_table VALUES (2, 1, 2, NULL);
Ale nie zachowuje się zgodnie z oczekiwaniami, ponieważ zgodnie z dokumentacją dwie NULL
wartości nie są ze sobą porównywane, więc obie wstawki przebiegają bezbłędnie.
Jak mogę zagwarantować moje wyjątkowe ograniczenie, nawet jeśli tak id_C
jest NULL
w tym przypadku? Właściwie prawdziwe pytanie brzmi: czy mogę zagwarantować tego rodzaju wyjątkowość w „czystym sql”, czy też muszę go wdrożyć na wyższym poziomie (w moim przypadku java)?
postgresql
constraint
null
unique-constraint
Manuel Leduc
źródło
źródło
(1,2,1)
i(1,2,2)
w(A,B,C)
kolumnach. Czy(1,2,NULL)
należy zezwolić na dodanie, czy nie?Odpowiedzi:
Możesz to zrobić w czystym SQL . Utwórz częściowy unikalny indeks oprócz tego, który masz:
W ten sposób możesz wpisać
(a, b, c)
w tabeli:Ale żaden z nich po raz drugi.
Lub użyj dwóch
UNIQUE
indeksów częściowych i bez pełnego indeksu (lub ograniczenia). Najlepsze rozwiązanie zależy od szczegółów twoich wymagań. Porównać:Chociaż jest to eleganckie i wydajne rozwiązanie dla pojedynczej zerowalnej kolumny w
UNIQUE
indeksie, szybko wymyka się spod kontroli, by uzyskać więcej. Omówienie tego - i jak korzystać z UPSERT z częściowymi indeksami:Na bok
Nie ma zastosowania w przypadku identyfikatorów mieszanych bez podwójnych cudzysłowów w PostgreSQL.
Państwo może rozważyć
serial
kolumnę jako klucz podstawowy lubIDENTITY
kolumny w PostgreSQL 10 lub nowszej. Związane z:Więc:
Jeśli nie spodziewasz się więcej niż 2 miliardów wierszy (> 2147483647) przez cały okres użytkowania tabeli (w tym odpadów i wierszy usuniętych), rozważ
integer
(4 bajty) zamiastbigint
(8 bajtów).źródło
Miałem ten sam problem i znalazłem inny sposób na umieszczenie w tabeli unikatowej wartości NULL.
W moim przypadku pole
foreign_key_field
jest dodatnią liczbą całkowitą i nigdy nie będzie wynosić -1.Tak więc, aby odpowiedzieć na Manual Leduc, mogłoby być inne rozwiązanie
Zakładam, że identyfikatory nie będą wynosić -1.
Jaka jest zaleta tworzenia częściowego indeksu?
W przypadku, gdy nie masz klauzuli NOT NULL
id_a
,id_b
iid_c
możesz być NULL razem tylko raz.Przy częściowym indeksie 3 pola mogą być NULL więcej niż jeden raz.
źródło
COALESCE
może skutecznie ograniczać duplikaty, ale indeks nie byłby bardzo przydatny w zapytaniach, ponieważ jest indeksem wyrażeń, który prawdopodobnie nie pasuje do wyrażeń zapytań. To znaczy, chybaSELECT COALESCE(col, -1) ...
że nie trafiłbyś do indeksu.Wartość Null może oznaczać, że wartość nie jest w tej chwili znana dla tego wiersza, ale zostanie dodana, jeśli będzie znana, w przyszłości (na przykład
FinishDate
dla bieguProject
) lub że dla tego wiersza nie będzie można zastosować żadnej wartości (na przykładEscapeVelocity
dla czarnej dziuryStar
).Moim zdaniem zwykle lepiej jest znormalizować tabele, eliminując wszystkie wartości Null.
W twoim przypadku chcesz zezwolić
NULLs
w kolumnie, ale chcesz,NULL
aby dozwolona była tylko jedna . Dlaczego? Jaki to związek między dwiema tabelami?Być może możesz po prostu zmienić kolumnę
NOT NULL
i zapisać zamiastNULL
niej specjalną wartość (jak-1
), o której wiadomo, że nigdy się nie pojawia. To rozwiąże problem ograniczenia wyjątkowości (ale może mieć inne potencjalnie niepożądane skutki uboczne. Na przykład użycie-1
oznaczenia „nieznane / nie dotyczy” spowoduje wypaczenie dowolnej sumy lub średnich obliczeń w kolumnie. Lub wszystkie takie obliczenia będą musiały uwzględnij wartość specjalną i zignoruj ją).źródło