PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Valeur unique PostgreSQL sur plusieurs colonnes

Malheureusement, cela ne peut pas être résolu facilement avec de simples contraintes / index uniques (si cela peut être résolu avec eux).

Ce dont vous avez besoin, c'est d'une exclusion contrainte  :la possibilité d'exclure certaines lignes, en fonction de quelque chose comme la collision . Les contraintes uniques ne sont que des contraintes d'exclusion spécifiques (elles sont basées sur des collisions d'égalité ).

Donc, en théorie, il suffit d'exclure chaque row1 , où il y a déjà un row2 , pour laquelle cette expression est vraie :ARRAY[row1.cola, row1.colb] && ARRAY[row2.cola, row2.colb]

Cet index pourrait faire le travail (actuellement seulement gist les index prennent en charge les contraintes d'exclusion) :

ALTER TABLE table_name
  ADD CONSTRAINT table_name_exclusion
  EXCLUDE USING gist ((ARRAY[cola, colb]) WITH &&);

Mais malheureusement, il n'y a pas de classe d'opérateur par défaut pour les tableaux (qui utilise gist ). Il existe un intarray modules , qui en fournit un pour seulement integer tableaux, mais rien pour text tableaux.

Si vous voulez vraiment résoudre ce problème, vous pouvez toujours abuser du range type (par exemple, j'ai utilisé le -|- adjacent opérateur, qui gère tous les cas, qui ne peuvent pas être traités avec unique ) ...

-- there is no built-in type for text ranges neither,
-- but it can can be created fairly easily:
CREATE TYPE textrange AS RANGE (
  SUBTYPE = text
);

ALTER TABLE table_name
  ADD CONSTRAINT table_name_exclusion
  EXCLUDE USING gist ((textrange(least(cola, colb), greatest(cola, colb))) WITH -|-);

-- the exclusion constraint above does not handle all situations:

ALTER TABLE table_name
  ADD CONSTRAINT table_name_check
  CHECK (cola is distinct from colb); -- without this, empty ranges could be created,
                                      -- which are not adjacent to any other range

CREATE UNIQUE INDEX table_name_unique
  ON table_name ((ARRAY[least(cola, colb), greatest(cola, colb)]));
     -- without this, duplicated rows could be created,
     -- because ranges are not adjacent to themselves

... mais j'ai bien peur que votre problème d'origine puisse être résolu beaucoup plus facilement avec une petite refactorisation de la base de données ; ce qui nous amène à la question :quel problème voulez-vous résoudre avec cela ?