За съжаление, това не може да бъде решено лесно с прости уникални ограничения / индекси (ако изобщо може да бъде решено с тях).
Това, от което се нуждаете, е изключване ограничение :възможността за изключване на някои редове въз основа на нещо като сблъсък . Уникалните ограничения са просто специфични ограничения за изключване (те се основават на сблъсъци на равенство ).
Така че на теория просто трябва да изключите всеки row1
, където вече има row2
, за които този израз е верен:ARRAY[row1.cola, row1.colb] && ARRAY[row2.cola, row2.colb]
Този индекс може свърши работата (в момента само gist
индексите поддържат ограничения за изключване):
ALTER TABLE table_name
ADD CONSTRAINT table_name_exclusion
EXCLUDE USING gist ((ARRAY[cola, colb]) WITH &&);
Но за съжаление няма операторен клас по подразбиране за масиви (който използва gist
). Има intarray
модул
, което предоставя едно само за integer
масиви, но нищо за text
масиви.
Ако наистина искате да разрешите това, винаги можете да злоупотребите с range
типове
(напр. използвах съседния -|-
оператор, който обработва всички случаи, които не могат да бъдат обработени с 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
... но се опасявам, че вашият първоначален проблем може да бъде решен много по-лесно с малко рефакторинг на базата данни; което ни води до въпроса:какъв проблем искате да решите с това?