Opslaan als array (gedenormaliseerd)
Ik zou de aanvullende module intarray
overwegen die de handige (en snelle) functies biedt uniq()
en sort()
. In een typische moderne Postgres-installatie is het zo eenvoudig als:
CREATE EXTENSION intarray;
Met behulp van deze, een eenvoudige CHECK
beperking kan oplopend afdwingen arrays met onderscheiden elementen.
CHECK (uniq(sort(cat_arr)) = cat_arr)
U kunt aanvullend (optioneel) een trigger hebben die arraywaarden normaliseert ON INSERT OR UPDATE
automatisch. Dan kun je gewoon elke doorgeven array (mogelijk ongesorteerd en met dupes) en alles werkt gewoon. Vind ik leuk:
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();
De extra module intarray is optioneel, er zijn andere manieren:
Maar de intarray-functies leveren superieure prestaties.
Dan je kunt gewoon een UNIQUE
. maken beperking op de matrixkolom om de uniciteit van de hele matrix af te dwingen.
UNIQUE (cat_arr)
Twee dagen geleden schreef ik in dit gerelateerde antwoord meer over de voordelen van het combineren van (zeer strikte en betrouwbare) beperkingen met (minder betrouwbare maar handigere) triggers:
Als je voor elke combinatie alleen de ID hoeft op te slaan (en geen aanvullende informatie), zou dit goed genoeg moeten zijn.
Echter referentiële integriteit is op deze manier niet gemakkelijk te waarborgen. Er zijn (nog) geen externe sleutelbeperkingen voor array-elementen - zoals gedocumenteerd in uw link
:Als een van de categorieën wordt verwijderd of als u ID's wijzigt, worden verwijzingen verbroken ...
Genormaliseerd schema
Als u meer moet opslaan of liever een genormaliseerd schema gebruikt om referentiële integriteit af te dwingen of om een of andere reden, kunt u dat ook doen en een trigger toevoegen om een handgemaakte gematerialiseerde weergave (een redundante tabel) te vullen en uniciteit op een vergelijkbare manier afdwingen:
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)
);
Gerelateerd antwoord (niet voor unieke combinaties, maar voor unieke elementen) dat de trigger demonstreert: