PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Eindeutiger PostgreSQL-Wert über mehrere Spalten hinweg

Leider kann dies nicht einfach mit einfachen eindeutigen Contraints / Indizes gelöst werden (wenn es damit überhaupt gelöst werden kann).

Was Sie brauchen, ist ein Ausschluss Einschränkung :die Fähigkeit, einige Zeilen auszuschließen, basierend auf so etwas wie Kollision . Eindeutige Beschränkungen sind nur spezifische Ausschlussbeschränkungen (sie basieren auf Gleichheits-Kollisionen ).

Theoretisch müssen Sie also nur jede row1 ausschließen , wo bereits ein row2 vorhanden ist , für die dieser Ausdruck wahr ist:ARRAY[row1.cola, row1.colb] && ARRAY[row2.cola, row2.colb]

Dieser Index könnte den Job erledigen (aktuell nur gist Indizes unterstützen Ausschlussbeschränkungen):

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

Aber Leider gibt es keine Standardoperatorklasse für Arrays (die gist verwendet ). Es gibt einen intarray Modul , die nur einen für integer bereitstellt Arrays, aber nichts für text Arrays.

Wenn Sie das wirklich herausfinden wollen, können Sie den range Typen (Beispiel:Ich habe den nebenstehenden -|- verwendet Operator, der alle Fälle behandelt, die nicht mit unique behandelt werden können ) ...

-- 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

... aber ich fürchte, Ihr ursprüngliches Problem könnte mit ein wenig Datenbank-Refaktorisierung viel einfacher gelöst werden; was uns zu der frage bringt:welches problem willst du damit lösen?