UPSERT - INSERT ... ON CONFLICT завершается ошибкой с индексом на основе функции в качестве уникального ограничения «lower ()» - PullRequest
0 голосов
/ 14 февраля 2019

У меня есть таблица базы данных со столбцом code, которая использует индекс в нижнем регистре для предотвращения значений кода, отличающихся только регистром (например, 'XYZ' = 'xYZ' = 'xyz').Типичным способом в Postgresql является создание индекса на основе функций, например: CREATE UNIQUE INDEX mytable_lower_code_idx ON mytable (lower(code)).

Теперь у меня есть случай, когда мне нужно поведение upsert для этого столбца:

-- first insert
INSERT INTO mytable (code) VALUES ('abcd');

-- second insert, with upsert behaviour
INSERT INTO mytable (code) VALUES ('Abcd')
  ON CONFLICT (code) DO UPDATE
  SET code='Abcd';

Дляпри второй вставке я получаю нарушение уникального ключа: ERROR: duplicate key value violates unique constraint "mytable_lower_code_idx"

(я также пытался использовать ON CONFLICT ON CONSTRAINT mytable_lower_code_idx, но Postgresql говорит мне, что это ограничение не существует, поэтому, возможно, оно не рассматривает индекс как ограничение.)

Мой последний вопрос: есть ли способ заставить INSERT ... ON CONFLICT работать вместе с индексами в выражениях?Или я должен ввести физический индексированный строчный столбец для выполнения задачи?

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

Использование ON CONFLICT (lower(code)) DO UPDATE:

CREATE TABLE mytable (
    code text
);
CREATE UNIQUE INDEX mytable_lower_code_idx ON mytable (lower(code));
INSERT INTO mytable VALUES ('abcd');

INSERT INTO mytable (code) VALUES ('Abcd')
  ON CONFLICT (lower(code)) DO UPDATE
  SET code='Abcd';

SELECT * FROM mytable;

выходы

| code |
|------|
| Abcd |

Обратите внимание, что ON CONFLICT синтаксис позволяет цели конфликта бытьindex_expression (мой акцент):

ON CONFLICT conflict_target
, где conflict_target может быть одним из:

( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ]
    ON CONSTRAINT constraint_name

и index_expression:

Аналогично index_column_name, но используется для вывода выражений в столбцах table_name, появляющихся в определениях индекса (не в простых столбцах).Следует формат CREATE INDEX.

0 голосов
/ 14 февраля 2019

Попробуйте добавить свой индекс следующим образом:

CREATE UNIQUE INDEX CONCURRENTLY mytable_lower_code_idx 
ON mytable (lower(code));

ALTER TABLE mytable 
ADD CONSTRAINT unique_mytab_code
UNIQUE USING INDEX mytable_lower_code_idx ;

, а затем:

INSERT INTO mytable (code) VALUES ('abcd');

-- second insert, with upsert behaviour
INSERT INTO mytable (code) VALUES ('Abcd')
  ON CONFLICT ON CONSTRAINT unique_mytab_code DO UPDATE
  SET code='Abcd';
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...