问题
Suppose, I have the following table:
CREATE TABLE "user" (
id BIGINT PRIMARY KEY NOT NULL,
phone1 VARCHAR,
phone2 VARCHAR
);
And I need to implement the following limitation: all phone numbers (if any) in table must be unique.
i.e database should not allow any of the following situations:
id | phone1 | phone2
1 | 111 | 111
id | phone1 | phone2
1 | 111 | NULL
2 | 111 | NULL
id | phone1 | phone2
1 | 111 | NULL
2 | NULL | 111
I know how to implement constraints for first two examples, but I'm stuck with the third one. Is there any way to do this?
回答1:
try an old trick:
db=# create unique index on "user" (least(phone1,phone2), greatest(phone1,phone2));
CREATE INDEX
Time: 14.507 ms
db=# insert into "user" values(1,111,111);
INSERT 0 1
Time: 35.017 ms
rest will fail:
db=# insert into "user" values(2,111,null);
ERROR: duplicate key value violates unique constraint "user_least_greatest_idx"
DETAIL: Key ((LEAST(phone1, phone2)), (GREATEST(phone1, phone2)))=(111, 111) already exists.
Time: 10.323 ms
db=# insert into "user" values(2,null,111);
ERROR: duplicate key value violates unique constraint "user_least_greatest_idx"
DETAIL: Key ((LEAST(phone1, phone2)), (GREATEST(phone1, phone2)))=(111, 111) already exists.
Time: 5.553 ms
db=# insert into "user" values(1,111,111);
ERROR: duplicate key value violates unique constraint "user_pkey"
DETAIL: Key (id)=(1) already exists.
Time: 11.067 ms
回答2:
You cannot easily do this. The least()
/greatest()
approach will not work in all cases.
Postgres does have some fancy index operations. But the best way is to use a junction table. For instance:
create table userPhones (
userPhoneId bigint primary key ,
userId bigint references users(id),
phone_counter int check (phone_counter in (1, 2)),
phone varchar,
unique (userId, phone_counter),
unique(phone)
);
This also limits the number of phone numbers to 2 for each user.
来源:https://stackoverflow.com/questions/51628569/unique-value-constraint-across-multiple-columns