Bohužel to nelze snadno vyřešit pomocí jednoduchých jedinečných omezení / indexů (pokud to lze s nimi vůbec vyřešit).
Co potřebujete, je výjimka omezení :možnost vyloučit některé řádky na základě něčeho jako kolize . Jedinečná omezení jsou pouze specifická omezení vyloučení (jsou založena na kolizích rovnosti ).
Teoreticky tedy stačí vyloučit každý row1
, kde již existuje row2
, pro které platí tento výraz:ARRAY[row1.cola, row1.colb] && ARRAY[row2.cola, row2.colb]
Tento index mohl udělat práci (v současnosti pouze gist
indexy podporují omezení vyloučení):
ALTER TABLE table_name
ADD CONSTRAINT table_name_exclusion
EXCLUDE USING gist ((ARRAY[cola, colb]) WITH &&);
Ale bohužel neexistuje žádná výchozí třída operátorů pro pole (která používá gist
). Existuje intarray
modul
, který poskytuje jeden pouze pro integer
pole, ale nic pro text
pole.
Pokud to opravdu chcete vyřešit, můžete vždy zneužít range
typy
(např. jsem použil sousední -|-
operátor, který zpracovává všechny případy, které nelze zpracovat pomocí 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
... ale obávám se, že váš původní problém by mohl být vyřešen mnohem jednodušeji pomocí malého refaktorování databáze; což nás přivádí k otázce:jaký problém tímto chcete vyřešit?