sql >> Base de Datos >  >> RDS >> PostgreSQL

Valor único de PostgreSQL en varias columnas

Lamentablemente, esto no se puede resolver fácilmente con restricciones/índices únicos simples (si es que se puede resolver con ellos).

Lo que necesita es una exclusión restricción :la capacidad de excluir algunas filas, en función de algo como colisión . Las restricciones únicas son solo restricciones de exclusión específicas (se basan en colisiones de igualdad ).

Entonces, en teoría, solo necesita excluir cada row1 , donde ya existe una row2 , para lo cual esta expresión es verdadera:ARRAY[row1.cola, row1.colb] && ARRAY[row2.cola, row2.colb]

Este índice podría hacer el trabajo (actualmente solo gist los índices admiten restricciones de exclusión):

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

Pero desafortunadamente, no existe una clase de operador predeterminada para matrices (que usa gist ). Hay un intarray módulo , que proporciona uno solo para integer arreglos, pero nada para text matrices.

Si realmente quiere resolver esto, siempre puede abusar del range tipos (por ejemplo, usé el -|- adyacente operador, que maneja todos los casos, que no se pueden manejar con 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

... pero me temo que su problema original podría resolverse mucho más fácilmente con una pequeña refactorización de la base de datos; lo que nos lleva a la pregunta:¿qué problema quieres resolver con esto?