【问题标题】:UPSERT - INSERT ... ON CONFLICT fails with a function based index as 'lower()' unique constraintUPSERT - INSERT ... ON CONFLICT 失败,基于函数的索引作为 'lower()' 唯一约束
【发布时间】:2019-02-13 21:08:07
【问题描述】:

我有一个带有 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 与表达式索引一起工作?或者我必须引入一个物理索引的小写列来完成任务?

【问题讨论】:

    标签: postgresql unique-constraint lowercase upsert


    【解决方案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 格式。

    【讨论】:

      【解决方案2】:

      尝试按如下方式添加索引:

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

      【讨论】:

      • 谢谢! - 我仍然接受了另一个答案,因为它不需要添加额外的约束。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-27
      • 1970-01-01
      • 1970-01-01
      • 2016-12-21
      相关资源
      最近更新 更多