我通常知道PostgreSQL中的部分唯一索引,但是我需要设置一个我认为不适合部分索引领域的约束。或者也许有一种表达方式。
最小示例
CREATE TABLE table (user INT, type INT, flag BOOL, text VARCHAR (50));
要求是:
user
可以有多个相同type
的行,但前提是flag
为假。
如果user
的行具有特定的type
且flag
设置为true,则该user
不会有其他行,并且type
。
例如,如果表具有以下行:
| user | type | flag | text |
| 1 | 1 | false | foo |
| 1 | 1 | false | bar |
那么我们就不能插入(1、1,true和“任何”)
如果表具有:
| user | type | flag | text |
| 1 | 1 | true | foo |
我们无法插入(1,1,false,'bar')或(1,1,true,'baz')
是否有一种表达约束的方法,例如PostgreSQL中的约束?
答案 0 :(得分:2)
您需要partial unique index和exclusion constraint的组合。不幸的是,在排除约束中没有可用于布尔列的运算符系列,因此可以使用整数列。 btree_gist extension是模拟整数列的摘要索引所必需的。
create extension if not exists btree_gist;
表定义(标识符稍作修改):
drop table if exists my_table;
create table my_table (
user_id integer,
type_id integer,
flag integer check (flag in (0, 1)),
text varchar (50),
exclude using gist (user_id with =, type_id with =, flag with <>)
);
create unique index on my_table (user_id, type_id) where flag = 1;
示例性插入:
insert into my_table
values
(1, 1, 0, 'foo'),
(1, 1, 0, 'bar'),
(2, 2, 1, 'foo');
INSERT 0 3
insert into my_table
values
(1, 1, 1, 'whatever');
ERROR: conflicting key value violates exclusion constraint "my_table_user_id_type_id_flag_excl"
DETAIL: Key (user_id, type_id, flag)=(1, 1, 1) conflicts with existing key (user_id, type_id, flag)=(1, 1, 0).
insert into my_table
values
(2, 2, 0, 'whatever');
ERROR: conflicting key value violates exclusion constraint "my_table_user_id_type_id_flag_excl"
DETAIL: Key (user_id, type_id, flag)=(2, 2, 0) conflicts with existing key (user_id, type_id, flag)=(2, 2, 1).
insert into my_table
values
(2, 2, 1, 'whatever');
ERROR: duplicate key value violates unique constraint "my_table_user_id_type_id_idx"
DETAIL: Key (user_id, type_id)=(2, 2) already exists.