Niestandardowe ograniczenie unikatowej kolumny, wymuszane tylko wtedy, gdy jedna kolumna ma określoną wartość

19

Czy możliwe jest niestandardowe ograniczenie kolumny w następujący sposób? Załóżmy, że mam dwa cols subseti typeoba ciągi (chociaż typy danych prawdopodobnie nie mają znaczenia).

Jeśli typejest „prawdziwe”, to chcę, aby kombinacja typei subsetbyła unikalna. W przeciwnym razie nie ma ograniczeń. Używam PostgreSQL 8.4 na Debianie.

Faheem Mitha
źródło

Odpowiedzi:

31

Innymi słowy, chcesz subsetbyć wyjątkowy, jeśli type = 'true'. Częściowy indeks unikalny zrobi, że:

CREATE UNIQUE INDEX tbl_some_name_idx ON tbl (subset) WHERE type = 'true';

W ten sposób możesz nawet tworzyć kombinacje z NULLunikalnymi, co inaczej nie jest możliwe - jak szczegółowo opisano w pokrewnej odpowiedzi:
Wielokolumnowe ograniczenie PostgreSQL i wartości NULL

Erwin Brandstetter
źródło
Dzięki Erwin. Nie widziałem tej opcji, kiedy przeglądałem dokumentację. Bardziej bezpośredni link to postgresql.org/docs/current/interactive/indexes-partial.html . Zobacz przykład 11-3.
Faheem Mitha
@FaheemMitha: I połączone jeden poziom wyżej, ponieważ trzeba połączyć się częściowe indeksu z indeksu unikalnego .
Erwin Brandstetter
1
@Erwin Ta strona (o częściowych indeksach) ma przykład z częściowym unikalnym indeksem.
ypercubeᵀᴹ
@ypercube: Ach, racja. To lepszy link. Zmieniłem odpowiedź, aby wskazać na ostatni rozdział.
Erwin Brandstetter
6

Jest to uzupełnienie powyższej odpowiedzi Erwina, ale PostgreSQL obsługuje wiele rodzajów indeksów. Zasadniczo nie wykluczają się one wzajemnie. Możesz myśleć o nich jako:

  • Metoda indeksu (btree, GiST, GIN itp.). Wybierz jeden, jeśli to konieczne (domyślnie btree)
  • Częściowe lub pełne. Jeśli częściowe, użyj klauzuli where
  • Bezpośredni lub funkcjonalny. Możesz indeksować dane wyjściowe funkcji.
  • Unikalny lub nieunikalny

Wszystkie te można łączyć na różne sposoby. Wszystko, co tutaj robisz, to używanie unikalnych i częściowych funkcji, dzięki czemu uzyskujesz częściowe unikalne indeksy (które są niezwykle przydatne, gdy się dowiadujesz.

Załóżmy jednak, że chcesz mieć indeks bez rozróżniania wielkości liter w polu podzestawu, w którym typ jest prawdziwy. Następnie dodaj definicję funkcjonalną:

CREATE INDEX my_index_name_idx_u ON tbl (lower(subset)) WHERE type;

Zauważ, że tworzy to unikalny indeks na wyjściu funkcji lower () wywoływanej w atrybucie podzestawu, gdzie typ jest prawdziwy.

Chris Travers
źródło
Tak więc indeks w odpowiedzi Erwina jest bezpośredni, podczas gdy ten w twoim przykładzie funkcjonalny, prawda?
Faheem Mitha
@FaheemMitha: Poprawnie.
Erwin Brandstetter