PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Valor exclusivo do PostgreSQL em várias colunas


Infelizmente, isso não pode ser resolvido facilmente com restrições / índices únicos simples (se puder ser resolvido com eles).

O que você precisa é de uma exclusão restrição :a capacidade de excluir algumas linhas, com base em algo como colisão . Restrições exclusivas são apenas restrições de exclusão específicas (elas são baseadas em colisões de igualdade ).

Então, em teoria, você só precisa excluir cada row1 , onde já existe um row2 , para a qual esta expressão é verdadeira:ARRAY[row1.cola, row1.colb] && ARRAY[row2.cola, row2.colb]

Este índice poderia fazer o trabalho (atualmente apenas gist índices suportam restrições de exclusão):
ALTER TABLE table_name
  ADD CONSTRAINT table_name_exclusion
  EXCLUDE USING gist ((ARRAY[cola, colb]) WITH &&);

Mas infelizmente, não existe uma classe de operador padrão para arrays (que usa gist ). Existe um intarray módulo , que fornece um para apenas integer matrizes, mas nada para text matrizes.

Se você realmente quiser resolver isso, você sempre pode abusar do range tipos (por exemplo, usei o -|- adjacente operador, que trata de todos os casos, que não podem ser tratados com 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

... mas temo que seu problema original possa ser resolvido muito mais facilmente com um pouco de refatoração de banco de dados; o que nos leva à pergunta:qual problema você quer resolver com isso?