Postgres中与其他行相关的部分唯一索引

时间:2019-05-19 20:51:36

标签: postgresql unique-constraint

我通常知道PostgreSQL中的部分唯一索引,但是我需要设置一个我认为不适合部分索引领域的约束。或者也许有一种表达方式。

最小示例

CREATE TABLE table (user INT, type INT, flag BOOL, text VARCHAR (50));

要求是:

  1. user可以有多个相同type的行,但前提是flag为假。

  2. 如果user的行具有特定的typeflag设置为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中的约束?

1 个答案:

答案 0 :(得分:2)

您需要partial unique indexexclusion 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.