I have PostgreSQL table
id ColA ColB
------------------
1 'a' 'b'
2 'c' 'd'
I want to make values in ColA and ColB to be unique across both columns i.e. any of these inserts would be forbidden:
INSERT INTO table (ColA,ColB) values('a','e');
INSERT INTO table (ColA,ColB) values('z','a');
INSERT INTO table (ColA,ColB) values('d','g');
and any of these inserts would be allowed:
INSERT INTO table (ColA,ColB) values('z','e');
INSERT INTO table (ColA,ColB) values('l','k');
So
CONSTRAINT unique_name UNIQUE (ColA,ColB)
is not suited, because it will allow any of previous 4 inserts.
Sadly, this cannot be solved easily with simple unique contraints / indexes (if it can be solved with them at all).
What you need, is an exclusion constraint: the ability to exclude some rows, based on something like collision. Unique constraints are just specific exclusion constraints (they are based on equality collisions).
So, in theory, you just need to exclude every
row1
, where there is already arow2
, for which this expression is true:ARRAY[row1.cola, row1.colb] && ARRAY[row2.cola, row2.colb]
This index could do the job (currently only
gist
indexes support exclusion constraints):But unfortunately, there is no default operator class for arrays (which uses
gist
). There is anintarray
module, which provides one for onlyinteger
arrays, but nothing fortext
arrays.If you really want to work this out, you can always abuse the
range
types (f.ex. I used the adjacent-|-
operator, which handles all the cases, which cannot be handled withunique
) ...... but I'm afraid, your original problem could be solved much easier with a little database refactoring; which brings us to the question: what problem, do you want to solve with this?