Как выполнить массовое обновление с переопределением ограничения «CREATE UNIQUE INDEX»? - PullRequest
1 голос
/ 14 марта 2020

У меня есть таблица

CREATE TABLE my_table (
    ranking    INTEGER NOT NULL,
    name         TEXT  NOT NULL,
    is_deleted BOOLEAN NOT NULL
);
CREATE UNIQUE INDEX exists_const ON my_table ranking WHERE (is_deleted = FALSE);

| ranking |  name  | is_deleted |
|   1     |  A     |   true     |
|   2     |  B     |   true     |
|   1     |  C     |   true     |
|   1     |  D     |   false    |
|   2     |  E     |   false    |
|   3     |  F     |   false    |

Поэтому, когда я хочу обновить новый рейтинг для D, E, F, чтобы он был

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

|   1     |  F     |   false    |
|   2     |  D     |   false    |
|   3     |  E     |   false    |

, у меня есть duplicate key value violates unique constraint "exists_const" ОШИБКА. Даже если новые строки не будут иметь дубликатов вообще. Как я могу выполнить такое обновление?

1 Ответ

1 голос
/ 14 марта 2020

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