Przechowuj jako tablicę (zdenormalizowaną)
Rozważę dodatkowy moduł intarray
który zapewnia wygodne (i szybkie) funkcje uniq()
i sort()
. W typowej nowoczesnej instalacji Postgresa jest to tak proste, jak:
CREATE EXTENSION intarray;
Korzystając z nich, proste CHECK
ograniczenie może wymuszać wznoszące tablice z różnymi elementy.
CHECK (uniq(sort(cat_arr)) = cat_arr)
Możesz dodatkowo (opcjonalnie) mieć wyzwalacz, który normalizuje wartości tablicy ON INSERT OR UPDATE
automatycznie. Wtedy możesz po prostu przekazać dowolne tablica (prawdopodobnie nieposortowana iz duplikatami) i wszystko po prostu działa. Na przykład:
CREATE OR REPLACE FUNCTION trg_search_insup_bef()
RETURNS trigger AS
$func$
BEGIN
NEW.cat_arr := uniq(sort(NEW.cat_arr);
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
CREATE TRIGGER insup_bef
BEFORE INSERT OR UPDATE OF cat_arr ON search
FOR EACH ROW
EXECUTE PROCEDURE trg_search_insup_bef();
Dodatkowa intarray modułów jest opcjonalna, istnieją inne sposoby:
Ale funkcje intarray zapewniają doskonałą wydajność.
Wtedy możesz po prostu utworzyć UNIQUE
ograniczenie w kolumnie tablicy, aby wymusić unikalność całej tablicy.
UNIQUE (cat_arr)
Pisałem więcej o zaletach łączenia (bardzo rygorystycznych i niezawodnych) ograniczeń z (mniej niezawodnymi, ale wygodniejszymi) wyzwalaczami w tej powiązanej odpowiedzi zaledwie dwa dni temu:
Jeśli dla każdej kombinacji wszystko, co musisz przechowywać w danej kategorii, to identyfikator (i żadnych dodatkowych informacji), powinno to wystarczyć.
Jednak , w ten sposób nie jest łatwo zapewnić integralność referencyjną. Nie ma ograniczeń kluczy obcych dla elementów tablicy (jeszcze) - jak udokumentowane w Twoim linku
:Jeśli jedna z kategorii zostanie usunięta lub zmienisz identyfikatory, odniesienia zostaną przerwane ...
Znormalizowany schemat
Jeśli potrzebujesz przechowywać więcej lub wolisz korzystać ze znormalizowanego schematu, aby wymusić integralność referencyjną lub z jakiegoś powodu, możesz to zrobić również i dodać wyzwalacz, aby wypełnić ręcznie wykonany widok zmaterializowany (nadmiarowa tabela) i wymuszać unikalność w podobny sposób:
CREATE TABLE search (
search_id serial PRIMARY KEY
, ... more columns
);
CREATE TABLE cat (
cat_id serial PRIMARY KEY
, cat text NOT NULL
);
CREATE TABLE search_cat (
search_id int REFERENCES search ON DELETE CASCADE
, cat_id int REFERENCES cat
, PRIMARY KEY (search_id, cat_id)
);
Powiązana odpowiedź (nie dla unikalnych kombinacji, ale dla unikalnych elementów), która demonstruje wyzwalacz: