sql >> Databasteknik >  >> RDS >> PostgreSQL

PostgreSQL unika värde på flera kolumner

Tyvärr kan detta inte lösas enkelt med enkla unika kontraints/index (om det överhuvudtaget kan lösas med dem).

Det du behöver är en uteslutning begränsning :möjligheten att utesluta vissa rader, baserat på något som kollision . Unika begränsningar är bara specifika uteslutningsbegränsningar (de är baserade på jämställdhets-kollisioner ).

Så i teorin behöver du bara utesluta varje row1 , där det redan finns en row2 , för vilket uttrycket är sant:ARRAY[row1.cola, row1.colb] && ARRAY[row2.cola, row2.colb]

Detta index kunde gör jobbet (för närvarande bara gist index stöder uteslutningsbegränsningar):

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

Men tyvärr finns det ingen standardoperatörsklass för arrayer (som använder gist ). Det finns en intarray modul , som tillhandahåller en för endast integer matriser, men inget för text arrayer.

Om du verkligen vill lösa detta kan du alltid missbruka range typer (t.ex. använde jag den intilliggande -|- operator, som hanterar alla ärenden, som inte kan hanteras med 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

... men jag är rädd att ditt ursprungliga problem skulle kunna lösas mycket lättare med lite databasrefaktorering; vilket för oss till frågan:vilket problem, vill du lösa med detta?




  1. Hur man hanterar fel i SQL Server-kapslade transaktioner

  2. Gör en INSERT ... SELECT-sats atomic

  3. Hur SUBDATE() fungerar i MariaDB

  4. Tvetydig kolumnreferens i INFOGA ... VID KONFLIKT UPPDATERA