Uložit jako pole (denormalizované)
Zvažoval bych doplňkový modul intarray
který poskytuje pohodlné (a rychlé) funkce uniq()
a sort()
. V typické moderní instalaci Postgres je to stejně snadné jako:
CREATE EXTENSION intarray;
Pomocí těchto jednoduchých CHECK
omezení může vynutit vzestupně pole s výraznými prvky.
CHECK (uniq(sort(cat_arr)) = cat_arr)
Můžete dodatečně (volitelně) mít spouštěč, který normalizuje hodnoty pole ON INSERT OR UPDATE
automaticky. Pak stačí předat jakýkoli pole (možná netříděné a s dupy) a všechno prostě funguje. Jako:
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();
Přídavný modul intarray je volitelný, existují další způsoby:
Ale funkce intarray poskytují vynikající výkon.
Potom stačí vytvořit UNIQUE
omezení ve sloupci pole, aby se vynutila jedinečnost celého pole.
UNIQUE (cat_arr)
Před dvěma dny jsem psal více o výhodách kombinace (velmi přísných a spolehlivých) omezení s (méně spolehlivými, ale pohodlnějšími) spouštěči v této související odpovědi:
Pokud pro každou kombinaci potřebujete pro každou kategorii uložit pouze ID (a žádné další informace), mělo by to stačit.
Nicméně , referenční integrita není tímto způsobem snadno zajištěna. Pro prvky pole (zatím) neexistují žádná omezení cizího klíče – jako zdokumentované ve vašem odkazu
:Pokud je jedna z kategorií odstraněna nebo změníte ID, reference se přeruší ...
Normalizované schéma
Pokud potřebujete uložit více nebo byste raději použili normalizované schéma k vynucení referenční integrity nebo z nějakého důvodu, můžete to udělat také a přidat spouštěč pro naplnění ručně vytvořeného materializovaného pohledu (nadbytečná tabulka) a vynutit jedinečnost podobným způsobem:
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)
);
Související odpověď (ne pro jedinečné kombinace, ale pro jedinečné prvky), která demonstruje spouštěč: