39

使用 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 | ...
4

2 回答 2

69

ON CONFLICT构造需要一个UNIQUE约束才能工作。从有关INSERT .. ON CONFLICT条款的文档中:

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

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

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

如果要插入的行与表中已有的行匹配这两个值,则代替INSERT,执行UPDATE

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  
于 2016-04-22T16:58:18.457 回答
10

作为当前接受的答案的简化替代方案,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;
于 2017-10-25T20:53:01.933 回答