sql >> Database >  >> RDS >> PostgreSQL

Unieke PostgreSQL-waarde over meerdere kolommen

Helaas kan dit niet eenvoudig worden opgelost met eenvoudige unieke beperkingen / indexen (als het al met hen kan worden opgelost).

Wat je nodig hebt, is een uitsluiting beperking :de mogelijkheid om enkele rijen uit te sluiten, op basis van bijvoorbeeld botsing . Unieke beperkingen zijn slechts specifieke uitsluitingsbeperkingen (ze zijn gebaseerd op gelijkheid botsingen ).

Dus in theorie hoef je alleen elke row1 . uit te sluiten , waar er al een row2 . is , waarvoor deze uitdrukking waar is:ARRAY[row1.cola, row1.colb] && ARRAY[row2.cola, row2.colb]

Deze index zou doe het werk (momenteel alleen gist indexen ondersteunen uitsluitingsbeperkingen):

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

Maar helaas is er geen standaard operatorklasse voor arrays (die gebruikmaakt van gist ). Er is een intarray module , die er een biedt voor slechts integer arrays, maar niets voor text arrays.

Als je dit echt wilt oplossen, kun je altijd misbruik maken van de range soorten (bijv. ik gebruikte de aangrenzende -|- operator, die alle zaken afhandelt, die niet kunnen worden afgehandeld met 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

... maar ik ben bang dat je oorspronkelijke probleem veel gemakkelijker zou kunnen worden opgelost met een beetje refactoring van de database; wat ons bij de vraag brengt:welk probleem wil je hiermee oplossen?




  1. Sorteerbare UUID's en overschrijven van ActiveRecord::Base

  2. Python Twisted en databaseverbindingen

  3. SQL Select inclusief gegevenstype en gegevenswaarden

  4. straal zoeken op breedtegraad / lengtegraad