Stocker en tant que tableau (dénormalisé)
Je considérerais le module supplémentaire intarray
qui fournit les fonctions pratiques (et rapides) uniq()
et sort()
. Dans une installation Postgres moderne typique, c'est aussi simple que :
CREATE EXTENSION intarray;
En utilisant ceux-ci, un simple CHECK
la contrainte peut appliquer ascendant tableaux avec distinct éléments.
CHECK (uniq(sort(cat_arr)) = cat_arr)
Vous pouvez en plus (optionnellement) avoir un déclencheur qui normalise les valeurs du tableau ON INSERT OR UPDATE
automatiquement. Ensuite, vous pouvez simplement passer tout tableau (éventuellement non trié et avec des dupes) et tout fonctionne. Comme :
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();
Le module supplémentaire intraray est facultatif, il existe d'autres moyens :
Mais les fonctions intraray offrent des performances supérieures.
Alors vous pouvez simplement créer un UNIQUE
contrainte sur la colonne du tableau pour appliquer l'unicité de l'ensemble du tableau.
UNIQUE (cat_arr)
J'ai écrit plus sur les avantages de combiner des contraintes (très strictes et fiables) avec des déclencheurs (moins fiables mais plus pratiques) dans cette réponse connexe il y a tout juste deux jours :
Si, pour chaque combinaison, tout ce que vous avez besoin de stocker par catégorie est l'ID (et aucune information supplémentaire), cela devrait suffire.
Cependant , l'intégrité référentielle n'est pas facilement assurée de cette façon. Il n'y a pas (encore) de contraintes de clé étrangère pour les éléments de tableau - comme documenté dans votre lien
:Si une des catégories est supprimée ou que vous changez d'identifiants, les références cassent...
Schéma normalisé
Si vous avez besoin de stocker plus ou si vous préférez utiliser un schéma normalisé pour appliquer l'intégrité référentielle ou pour une raison quelconque, vous pouvez également le faire et ajouter un déclencheur pour remplir une vue matérialisée faite à la main (une table redondante) et appliquer l'unicité de la même manière :
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)
);
Réponse connexe (pas pour des combinaisons uniques, mais pour des éléments uniques) qui illustre le déclencheur :