使用更新部分中源表中的值的具有ON CONFLICT的UPSERT


18

鉴于:

CREATE TABLE A (
PK_A INT8 NOT NULL,
A INT8,
PRIMARY KEY (PK_A)
);

CREATE TABLE B (
PK_B INT8 NOT NULL,
B INT8,
PRIMARY KEY (PK_B)
);

该查询:

insert into table_b (pk_b, b) 
select pk_a,a from table_a 
on conflict (b) do update set b=a;

导致以下错误:

ERROR:  column "a" does not exist
LINE 1: ...elect pk_a,a from table_a on conflict (b) do update set b=a;
                                                                 ^
HINT:  There is a column named "a" in table "*SELECT*", but it cannot be referenced from this part of the query.

参照的内容时如何进行更新table_a


5
CREATE TABLE A...创建表a,不是table_a
Abelisto

do update set b = a;无法找到“A”,因为表“B”,而不是子查询参考,尝试do update set b = (select a from a);
Patrick7

Answers:


25

多个问题。
您的设置已扩展:

CREATE TABLE a (
  pk_a int PRIMARY KEY 
, a int
, comment text  -- added column to make effect clear
);

CREATE TABLE b (
  pk_b int PRIMARY KEY
, b int 
, comment text
);

INSERT INTO a VALUES (1, 11, 'comment from a')
                   , (2, 22, 'comment from a');

INSERT INTO b VALUES (1, 77, 'comment from b');

这有效:

INSERT INTO b (pk_b, b, comment) 
SELECT pk_a, a, comment
FROM   a 
ON     CONFLICT (pk_b) DO UPDATE  -- conflict is on the unique column
SET    b = excluded.b;            -- key word "excluded", refer to target column

结果:

TABLE b;

 pk_b | b  |    comment
------+----+----------------
    1 | 11 | comment from b   -- updated
    2 | 22 | comment from a   -- inserted

问题所在

  1. 您很困惑,table_a并且A在演示中(如@Abelisto评论)。

    使用合法的,小写的,未加引号的标识符有助于避免混淆。

  2. 就像提到的@Ziggy一样,ON CONFLICT仅适用于实际的唯一性或排除约束冲突手册:

    可选ON CONFLICT子句指定引发唯一违反或排除约束违反错误的替代操作。

    因此,ON CONFLICT (b)无法工作,没有约束。ON CONFLICT (pk_b)作品。

  3. 就像也提到了@Ziggy一样,表名称在该UPDATE部分中不可见手册:

    中的SETWHERE子句ON CONFLICT DO UPDATE可以使用表名(或别名)访问现有行,并可以使用特殊excluded表访问建议插入的行

    大胆强调我的。

  4. 您也不能在零件中使用表的列名UPDATE。它必须是目标行的列名。所以你真的想要:

    SET    b = excluded.b

    手册再次:

    请注意,所有每行BEFORE INSERT触发器的影响都反映在排除的值中,因为这些影响可能导致该行被排除在插入之外。


感谢您的解释,现在我知道为什么b = excluded.a不能正常工作了,在官方的Docu中有点隐藏了。
Patrick7'6

一个简单的衬里,用于诸如:“排除”指向要插入或保留在表中的新传入数据。
user92674

8

在PostgreSQL 9.5+中进行upsert时,必须使用别名引用排除的数据(插入失败的数据)excluded。另外,该on conflict选项必须引用键:(pk_b)而不是(b)。例如。

insert into table_b (pk_b, b) 
select pk_a,a from table_a 
on conflict (pk_b) do update set b=excluded.b;

有关更多信息,请参阅官方文档或upsert的简单介绍


该查询并没有工作。
shx 2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.