Частичный уникальный индекс в postgres по отношению к другим строкам - PullRequest
1 голос
/ 19 мая 2019

Я знаю о частичных уникальных индексах в PostgreSQL в целом, но мне нужно ввести ограничение, которое не вписывается в область частичных индексов, я думаю.Или, может быть, есть способ как-то выразить это.

Минимальный пример

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

Требования:

  1. A user может иметьнесколько строк одного и того же type, но только если flag имеет значение false.

  2. Если user имеет строку с определенным type и flag, установленным вtrue, тогда не может быть другой строки для этих user и type.

Так, если, например, в таблице есть следующие строки:

| user | type | flag  | text |
| 1    | 1    | false | foo  |
| 1    | 1    | false | bar  |

тогда мы не можем вставить (1, 1, истина, «что угодно»)


Также, если таблица имеет:

| user | type | flag | text |
| 1    | 1    | true | foo  |

, чем мы не можем вставить (1, 1, ложь, 'bar') nor (1, 1, true, 'baz')


Есть ли способ выразить такое ограничение в PostgreSQL?

1 Ответ

2 голосов
/ 20 мая 2019

Вам нужна комбинация частичного уникального индекса и исключающего ограничения .К сожалению, нет семейства операторов, которое можно было бы использовать для логического столбца в ограничении исключения, поэтому вместо него можно использовать целочисленный столбец.Расширение btree_gist необходимо для эмуляции индекса gist для целочисленных столбцов.

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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...