2015-06-11 19 views
5

Ich habe PostgreSQL TabellePostgreSQL eindeutigen Wert acreoss mehrere Spalten

id ColA ColB 
------------------ 
1  'a'  'b' 
2  'c'  'd' 

Ich möchte Werte in ColA und ColB machen, einzigartig zu sein über beide Spalten jeder dieser Einsätze, also würde verboten werden:

INSERT INTO table (ColA,ColB) values('a','e'); 
INSERT INTO table (ColA,ColB) values('z','a'); 
INSERT INTO table (ColA,ColB) values('d','g'); 

und jeder dieser Einsätze würden erlaubt:

INSERT INTO table (ColA,ColB) values('z','e'); 
INSERT INTO table (ColA,ColB) values('l','k'); 

So

CONSTRAINT unique_name UNIQUE (ColA,ColB) 

ist nicht geeignet, da es alle vorherigen 4 Einsätze erlaubt.

Antwort

2

Leider kann dies nicht einfach mit einfachen eindeutigen Einschränkungen/Indizes (wenn es überhaupt mit ihnen gelöst werden kann) gelöst werden.

Was Sie brauchen, ist ein exclusionconstraint: die Fähigkeit, einige Zeilen auszuschließen, basierend auf so etwas wie Kollision. Eindeutige Einschränkungen sind nur spezifische Ausschlussbedingungen (sie basieren auf der Gleichheit Kollisionen).

Also in der Theorie, man muss nur jeden row1 auszuschließen, in denen es bereits ein row2, für die dieser Ausdruck wahr ist: ARRAY[row1.cola, row1.colb] && ARRAY[row2.cola, row2.colb]

Dieser Index die Arbeit machen könnte (derzeit nur gist Indizes Unterstützung Ausschlussbedingungen):

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 module, der einen für nur integer Arrays bereitstellt, aber nichts für text Arrays.

Wenn Sie wirklich daran arbeiten wollen, können Sie immer die range types (zb ich den benachbarten -|- Operator verwendet, der alle Fälle behandelt, die nicht mit unique gehandhabt werden kann) missbrauchen ...

-- 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-Refactoring viel einfacher gelöst werden; Das bringt uns zu der Frage: Welches Problem, willst du damit lösen?

Verwandte Themen