UPSERT-INSERT ... ON CONFLICT失败,基于函数的索引作为“ lower()”唯一约束

时间:2019-02-13 21:08:08

标签: postgresql unique-constraint lowercase upsert

我有一个带有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 :(得分:1)

尝试如下添加索引:

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';

答案 1 :(得分:1)

使用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 syntax 允许冲突目标为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格式。