【问题标题】:How to use postgres Insert ....ON CONFLICT DO UPDATE when inserting from select statement从select语句插入时如何使用postgres Insert ....ON CONFLICT DO UPDATE
【发布时间】:2020-07-01 21:47:45
【问题描述】:

我有以下 3 张桌子。请原谅表名,它们是通用数据库结构命名约定的一部分。

          table: tbl_331
          id (primary key, integer)
          field_3 (text)

          table: tbl_329_customid
          id (primary key, integer)
          fullname (text)

          table: tbl_331_to_tbl_329_field
          tbl_331_id (integer)
          tbl_329_id (integer)
          primary key (tbl_331_id, tbl_329_id)

我想编写一个查询,它将值插入到多对多表中:tbl_331_to_tbl_320_field 使用匹配值。如果我使用 DO NOTHING 参数,则此方法有效。

此语句用于插入找到匹配的值。

    insert into schema_1.tbl_331_to_tbl_329_field_3 
    select  X.id, S.id from schema_1.tbl_329 S 
    JOIN schema_1.tbl_331_customid X on S.field_3=x.fullname
    ON CONFLICT DO NOTHING

但我想使用 DO UPDATE,所以如果有冲突,它将更新第二个 id (S.id)。 例如,如果我将 S.field_3 中的值更改为与新 ID 匹配的其他值,我想更新这个多对多表中的 ID。

   insert into schema_1.tbl_331_to_tbl_329_field_3 
    select  X.id, S.id from schema_1.tbl_329 S 
    JOIN schema_1.tbl_331_customid X on S.field_3=x.fullname
    ON CONFLICT ( tbl_331_id, tbl_329_id ) DO UPDATE set S.id = EXCLUDED.id

“这导致列“id”的错误消息不明确。 "

如果我尝试使用这样的别名:

    insert into schema_1.tbl_331_to_tbl_329_field_3 
    select  X.id, S.id as myalias from schema_1.tbl_329 S 
    JOIN schema_1.tbl_331_customid X on S.field_3=x.fullname
    ON CONFLICT ( tbl_331_id, tbl_329_id ) DO UPDATE set S.id = myalias

我得到“列 myalias 不存在”

我对 DO UPDATE 的这种语法非常陌生。我的假设是在 ON CONFLICT 之后,您必须指定它会发生冲突的唯一键/主键,然后告诉它要更新什么。

我将如何编写它以更新匹配的新匹配 ID?

【问题讨论】:

  • on conflict 子句用于更新目标表中的行(此处为tbl_331_to_tbl_329_field_3),而不是源表中的行...这是您要执行的操作吗?跨度>
  • 是的,该表中有 2 个键。 tbl_331_id 和 tbl_329_id 。在这种情况下,如果有冲突,我想更新 tbl_329_id。
  • 这对我来说没有意义。此列是 on conflict 目标的一部分,因此您已经知道该值是相同的:更新它实际上不会更改该值。
  • 我认为问题在于我想要一个单一的键组合,而不是多对多......这是允许的。需要重新配置表。

标签: postgresql postgresql-9.5


【解决方案1】:
insert into schema_1.tbl_331_to_tbl_329_field_3 
select  X.id, S.id from schema_1.tbl_329 S 
JOIN schema_1.tbl_331_customid X on S.field_3=x.fullname
ON CONFLICT ( tbl_331_id, tbl_329_id ) DO UPDATE set S.id = EXCLUDED.id
  1. 这种UPDATE 的上下文只是名为EXCLUDED 的特殊表本身。从 UPDATE 中看不到您的输入表,您只能看到冲突记录 (EXCLUDED) 以及您尝试将它们插入的字段(schema_1.tbl_331_to_tbl_329_field_3 的列)。因此,您的S 无法访问,也没有必要这样做-在ON CONFLICT ... DO UPDATE 中,您正在解决传入数据与目标表中已有数据之间的冲突-Postgres 不介意您从哪里获得它甚至不试图记住。
  2. ERROR: column reference "id" is ambiguous 非常不直观。即使您可以随意为输入中的列起别名 - 只要它们的顺序和类型与您的目标匹配 - 在冲突时,它们会被处理,就好像它们已经在目标表中一样。因此,您的第一个id 和第二个id(或以后的myalias)实际上已经分别在EXCLUDED 表中被称为tbl_331_idtbl_329_id。您收到错误的原因是因为 Postgres 首先检查歧义并立即在该点抛出错误,然后再检查这些列是否属于您当前的上下文。
  3. S.id = myalias 没有多大意义,因为您刚刚别名为 myalias 的正是 S.id

【讨论】:

  • 谢谢,我意识到我的桌子设计不符合我的预期。
猜你喜欢
  • 2018-08-02
  • 2018-08-02
  • 2018-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
  • 2016-05-11
  • 1970-01-01
相关资源
最近更新 更多