3

Is there a constraint for values not being unique taking in consideration two columns, ex -

id  |  secondid
+---------------+
 3  |         4
 4  |         5

id  |  secondid
+---------------+
 3  |         4
 5  |         4

id  |  secondid
+---------------+
 4  |         4
 4  |         4

All the above cases are not okay, as 4 occurs twice in either id or secondid but something like

id  |  secondid
+---------------+
 1  |         3
 2  |         4

is okay as all the values in both the columns are unique, is there any way for me to achieve this without using any packages in postgresql?

4
  • 1
    @mu is too short: The other request is about tuples. They want to prevent (1,2) and (2,1) from both being in the table, because this is the same tuple, only with the values reversed. Spongerooski's request, however, is about single IDs. They want to prevent (1,2), (3,2) for instance, because an ID occurs more than once. Commented Jul 10, 2021 at 6:45
  • 1
    @ThorstenKettner Thanks, a second reading made me think it was more interesting than I first thought. Commented Jul 10, 2021 at 7:35
  • 1
    @Spongerooski . . . I suspect that something is wrong with your data model if you need to do this. You seem to have one id. There should be a table where that value is in one column. Commented Jul 10, 2021 at 11:51
  • Gordon has a point there. The real problem and hence the solution may really lie in the data model. You should really consider this (rather than just going with Gordon's answer, which perfectly solves the problem technically). Commented Jul 10, 2021 at 12:14

2 Answers 2

2

You can do this with a combination of an exclusion constraint and a check constraint. The check constraint is needed to prevent duplicates within one row.

create table t (
    id int,
    id2 int,
    check (id <> id2),
    exclude using gist ( (array[id, id2]) with &&)
);

The exclusion constraint operates by checking the specified operator never returns "true" for the column in the "new" row and all rows already in the table. It does not check values within the current row, which is why the check constraint is also needed.

Here is a db<>fiddle.

Sign up to request clarification or add additional context in comments.

2 Comments

I seem to be getting an error data type integer[] has no default operator class for access method "gist", do I need to have any extension for this?
1

You want a unique constraint that works on the two columns as if these were just one column. I think this is not possible directly. (Others may correct me.)

What you can do is create another table

create table check_unique_id (id int primary key);

and fill it via a trigger. I.e. every time you insert a row in your table, the trigger creates two rows in the check_unique_id table. If an ID occurs twice that other table will raise the exception.

3 Comments

I was hoping there was a direct way, this seems a bit hacky in my opinion but I'll definitely go with this if there isn't any other way, thank you :D
I think you can use an EXCLUDE constraint for this. If you CREATE EXTENSION intarray and then exclude using gist ((array[id, secondid]) with &&).
@mu is too short: Clever. Gordon has posted an answer using the same idea. Seems to work perfectly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.