Проблема может быть решена путем отсрочки проверки в конце транзакции, но вы не можете сделать это с помощью INDEX (насколько я знаю). Обходной путь, который я могу дать, это использовать EXCLUDE, как описано ниже:
CREATE TABLE my_table (
ranking INTEGER NOT NULL,
name TEXT NOT NULL,
is_deleted BOOLEAN NOT NULL,
EXCLUDE USING BTREE (ranking WITH =) WHERE (not is_deleted) DEFERRABLE
);
Внимание к 'DEFERRABLE'
Здесь для заполнения начальных данных:
insert into my_table ( ranking, name, is_deleted)
values
(1, 'A', true),
(2, 'B', true),
(1, 'C', true),
(1, 'D', false),
(2, 'E', false),
(3, 'F', false);
Now если вы выполните:
UPDATE "my_table" AS t
SET "ranking" = v."ranking"
FROM
(VALUES(1, 'F', 'false'),(2, 'D', 'false'), (3, 'E', 'false'))
AS v("ranking","name", "is_deleted")
WHERE v.name = t.name;
Это должно сработать.
И чтобы проверить уникальность, я проверил:
insert into my_table ( ranking, name, is_deleted)
values
(3, 'G', false);