UPSERT ที่มีความขัดแย้งโดยใช้ค่าจากตารางแหล่งที่มาในส่วน UPDATE


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;ไม่สามารถหา "เป็น" เพราะมีการอ้างอิงถึงตาราง "B" และไม่แบบสอบถามย่อยลองdo update set b = (select a from a);
Patrick7

คำตอบ:


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ส่วนหนึ่ง คู่มือ:

    SETและWHEREคำสั่งในการON CONFLICT DO UPDATEมีการเข้าถึงไปยังแถวที่มีอยู่โดยใช้ชื่อของตาราง (หรือนามแฝง) และแถวที่นำเสนอสำหรับการแทรกการใช้พิเศษexcludedตาราง

    เหมืองเน้นหนัก

  4. คุณไม่สามารถใช้ชื่อคอลัมน์ของตารางต้นฉบับในUPDATEส่วนได้ มันจะต้องเป็นชื่อคอลัมน์ของเป้าหมายแถว ดังนั้นคุณต้องการ:

    SET    b = excluded.b

    คู่มืออีกครั้ง:

    โปรดทราบว่าเอฟเฟกต์ของBEFORE INSERTทริกเกอร์ต่อแถวทั้งหมดจะแสดงเป็นค่าที่ยกเว้นเนื่องจากเอฟเฟกต์เหล่านั้นอาจส่งผลต่อแถวที่ถูกแยกออกจากการแทรก


ขอบคุณสำหรับคำอธิบายตอนนี้ฉันรู้แล้วว่าทำไมมันถึงใช้b = excluded.aงานไม่ได้มันถูกซ่อนอยู่ใน Docu อย่างเป็นทางการ
Patrick7

ง่าย ๆ หนึ่งซับสำหรับหุ่นเช่น: 'ยกเว้น' ชี้ไปที่ข้อมูลใหม่ที่เข้ามาซึ่งคุณต้องการที่จะแทรกหรือยังคงอยู่ในตาราง
92674

8

เมื่อทำการ upserts ใน PostgreSQL 9.5+ คุณต้องอ้างถึงข้อมูลที่ถูกแยกออก (นามแฝงที่ไม่สามารถแทรก) 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;

สำหรับข้อมูลเพิ่มเติมโปรดดูที่เอกสารอย่างเป็นทางการหรือคำแนะนำง่ายๆนี้เพื่อให้ง่ายขึ้น


แบบสอบถามนี้ไม่ทำงาน
shx
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.