Gem som array (denormaliseret)
Jeg ville overveje det ekstra modul intarray
der giver de praktiske (og hurtige) funktioner uniq()
og sort()
. I en typisk moderne Postgres-installation er det så nemt som:
CREATE EXTENSION intarray;
Ved at bruge disse, en simpel CHECK
begrænsning kan gennemtvinge stigende arrays med særskilte elementer.
CHECK (uniq(sort(cat_arr)) = cat_arr)
Du kan yderligere (valgfrit) have en trigger, der normaliserer matrixværdier ON INSERT OR UPDATE
automatisk. Så kan du bare passere hvilken som helst array (evt. usorteret og med duper) og alt virker bare. Ligesom:
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();
Det ekstra modul-inarray er valgfrit, der er andre måder:
Men inarray-funktionerne leverer overlegen ydeevne.
Så du kan bare oprette en UNIQUE
begrænsning på array-kolonnen for at fremtvinge entydighed af hele arrayet.
UNIQUE (cat_arr)
Jeg skrev mere om fordelene ved at kombinere (meget strenge og pålidelige) begrænsninger med (mindre pålidelige, men mere bekvemme) udløsere i dette relaterede svar for blot to dage siden:
Hvis det eneste, du behøver at gemme pr. kategori for hver kombination, er ID'et (og ingen yderligere oplysninger), burde dette være godt nok.
Men , referentiel integritet er ikke let sikret på denne måde. Der er ingen fremmednøgle-begrænsninger for array-elementer (endnu) - som dokumenteret i dit link
:Hvis en af kategorierne slettes, eller du ændrer ID'er, bryder referencerne ...
Normaliseret skema
Hvis du har brug for at gemme mere, eller du hellere vil gå med et normaliseret skema for at håndhæve referentiel integritet eller af en eller anden grund, kan du også gøre det og tilføje en trigger for at udfylde en håndlavet materialiseret visning (en redundant tabel) og håndhæve unikhed på en lignende måde:
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)
);
Relateret svar (ikke for unikke kombinationer, men for unikke elementer), der viser triggeren: