【问题标题】:How to correctly do upsert in postgres 9.5如何在 postgres 9.5 中正确执行 upsert
【发布时间】:2016-04-22 16:35:26
【问题描述】:

postgresql 9.5 的 upsert 语法正确,下面的查询显示 column reference "gallery_id" is ambiguous 错误,为什么?

var dbQuery = `INSERT INTO category_gallery (
  category_id, gallery_id, create_date, create_by_user_id
  ) VALUES ($1, $2, $3, $4)
  ON CONFLICT (category_id)
  DO UPDATE SET
  category_id = $1,
  last_modified_date = $3,
  last_modified_by_user_id = $4
  WHERE gallery_id = $2`;

我尝试将WHERE gallery_id = $2; 更改为WHERE category_gallery.gallery_id = $2; 然后显示错误there is no unique or exclusion constraint matching the ON CONFLICT specification,但我不想将gallery_id 或category_id 设置为唯一,因为我想确保两列都相同做更新......

如何在 postgres 9.5 中正确执行 upsert?

如果ON CONFLICT 需要唯一的列,我应该使用其他方法,如何?



我想确定多个列都冲突然后更新,正确的用法是什么

var dbQuery = `INSERT INTO category_gallery (
  category_id, gallery_id, create_date, create_by_user_id
  ) VALUES ($1, $2, $3, $4)
  ON CONFLICT (category_id, gallery_id)
  DO UPDATE SET
  category_id = $1,
  last_modified_date = $3,
  last_modified_by_user_id = $4
  WHERE gallery_id = $2`;


var dbQuery = `INSERT INTO category_gallery (
  category_id, gallery_id, create_date, create_by_user_id
  ) VALUES ($1, $2, $3, $4)
  ON CONFLICT (category_id AND gallery_id)
  DO UPDATE SET
  category_id = $1,
  last_modified_date = $3,
  last_modified_by_user_id = $4
  WHERE gallery_id = $2`;

表(category_id,gallery_id 不是唯一列)

category_id | gallery_id | create_date | create_by_user_id | last_modified_date | last_modified_by_user_id
1 | 1 | ...  
1 | 2 | ...
2 | 2 | ...
1 | 3 | ...

【问题讨论】:

    标签: sql postgresql upsert postgresql-9.5


    【解决方案1】:

    ON CONFLICT 构造需要UNIQUE 约束才能工作。来自INSERT .. ON CONFLICT clause的文档:

    可选的ON CONFLICT 子句指定引发唯一违规排除约束违规错误的替代操作。对于建议插入的每个单独的行,插入继续进行,或者,如果违反了由冲突目标指定的仲裁约束或索引,则采取替代冲突行动。 ON CONFLICT DO NOTHING 只是避免插入一行作为其替代操作。 ON CONFLICT DO UPDATE 更新与建议插入的行冲突的现有行作为其替代操作。

    现在,问题还不是很清楚,但您可能需要对 2 列组合的 UNIQUE 约束:(category_id, gallery_id)

    ALTER TABLE category_gallery
        ADD CONSTRAINT category_gallery_uq
        UNIQUE (category_id, gallery_id) ;
    

    如果要插入的行与 both 值与表上已有的行匹配,则使用 UPDATE 代替 INSERT

    INSERT INTO category_gallery (
      category_id, gallery_id, create_date, create_by_user_id
      ) VALUES ($1, $2, $3, $4)
      ON CONFLICT (category_id, gallery_id)
      DO UPDATE SET
        last_modified_date = EXCLUDED.create_date,
        last_modified_by_user_id = EXCLUDED.create_by_user_id ;
    

    您可以使用 UNIQUE 约束的任一列:

      ON CONFLICT (category_id, gallery_id) 
    

    或约束名称:

      ON CONFLICT ON CONSTRAINT category_gallery_uq  
    

    【讨论】:

    • 感谢您的回复,但我不希望 category_id 或 gallery_id 成为唯一列,有问题提及。我想确定 category_id 和 gallery_id 是否相同然后创建新行,请查看我的更新日期示例
    • 是的,如果已经存在 category_id=1 and gallery_id=3 然后更新,而不是插入。如果我想更新 category_id = 2 where gallery_id = 3 不起作用,我会使用你的脚本。还是我应该添加另一个更新脚本?
    • 我也试过这个INSERT INTO category_gallery ( category_id, gallery_id, create_date, create_by_user_id ) VALUES ($1, $2, $3, $4) ON CONFLICT (category_id, gallery_id) DO UPDATE SET category_id = $1, last_modified_date = EXCLUDED.create_date, last_modified_by_user_id = EXCLUDED.create_by_user_id WHERE category_gallery.gallery_id = $2
    • 我不理解你对update category_id = 2 where gallery_id = 3 的意思。你想用category_id = 2 and gallery_id = 3 插入/更新一行吗?我的脚本中没有WHERE
    • @ypercubeᵀᴹ 感谢您的回答,我已经解决了这个问题,但我的问题是通过约束名称调用 ON CONFLICT CONSTRAINT category_gallery_uq 不正确并且会导致语法错误,请考虑通过更改它来更新您的答案到ON CONFLICT ON CONSTRAINT category_gallery_uq。非常感谢
    【解决方案2】:

    作为the currently accepted answer 的简化替代方案,UNIQUE 约束可以在创建表时匿名添加:

    CREATE TABLE table_name (
        id  TEXT PRIMARY KEY,
        col TEXT,
        UNIQUE (id, col)
    );
    

    然后,upsert 查询变为(类似于已经回答的内容):

    INSERT INTO table_name (id, col) VALUES ($1, $2)
    ON CONFLICT (id, col)
        DO UPDATE SET col = $2;
    

    【讨论】:

      猜你喜欢
      • 2016-10-01
      • 2016-04-18
      • 2017-07-30
      • 1970-01-01
      • 2016-12-25
      • 2017-11-22
      • 2016-12-30
      • 2019-04-11
      • 2018-12-27
      相关资源
      最近更新 更多