跨多列的唯一值约束
Unique value constraint across multiple columns
假设,我有以下 table:
CREATE TABLE "user" (
id BIGINT PRIMARY KEY NOT NULL,
phone1 VARCHAR,
phone2 VARCHAR
);
并且我需要实施以下限制:table 中的所有 phone 个数字(如果有)必须是唯一的。
即数据库不应允许以下任何情况:
id | phone1 | phone2
1 | 111 | 111
id | phone1 | phone2
1 | 111 | NULL
2 | 111 | NULL
id | phone1 | phone2
1 | 111 | NULL
2 | NULL | 111
我知道如何为前两个示例实施约束,但我对第三个示例感到困惑。
有什么办法吗?
尝试一个老把戏:
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
休息会失败:
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
你不能轻易做到这一点。 least()
/greatest()
方法并非在所有情况下都有效。
Postgres 确实有一些奇特的索引操作。但最好的方法是使用一个连接点 table。例如:
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)
);
这也将每个用户的 phone 个号码限制为 2 个。
假设,我有以下 table:
CREATE TABLE "user" (
id BIGINT PRIMARY KEY NOT NULL,
phone1 VARCHAR,
phone2 VARCHAR
);
并且我需要实施以下限制:table 中的所有 phone 个数字(如果有)必须是唯一的。
即数据库不应允许以下任何情况:
id | phone1 | phone2
1 | 111 | 111
id | phone1 | phone2
1 | 111 | NULL
2 | 111 | NULL
id | phone1 | phone2
1 | 111 | NULL
2 | NULL | 111
我知道如何为前两个示例实施约束,但我对第三个示例感到困惑。 有什么办法吗?
尝试一个老把戏:
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
休息会失败:
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
你不能轻易做到这一点。 least()
/greatest()
方法并非在所有情况下都有效。
Postgres 确实有一些奇特的索引操作。但最好的方法是使用一个连接点 table。例如:
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)
);
这也将每个用户的 phone 个号码限制为 2 个。