UPSERT với ON CONFLICT bằng cách sử dụng các giá trị từ bảng nguồn trong phần CẬP NHẬT


17

Được:

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)
);

Truy vấn này:

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

gây ra lỗi sau:

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.

Làm thế nào để thực hiện cập nhật trong khi đề cập đến nội dung của table_a?


5
CREATE TABLE A...tạo bảng a, không table_a.
Abelisto

những do update set b = a;không thể tìm thấy "a" vì có tham chiếu đến Bảng "b" chứ không phải Subquery, hãy thửdo update set b = (select a from a);
Patrick7

Câu trả lời:


24

Nhiều vấn đề.
Thiết lập của bạn, được mở rộng:

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');

Những công việc này:

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

Kết quả:

TABLE b;

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

Vấn đề

  1. Bạn đang bối rối table_aAtrong bản demo của bạn (như @Abelisto đã nhận xét ).

    Sử dụng định danh hợp pháp, chữ thường, không trích dẫn giúp tránh nhầm lẫn.

  2. Giống như @Ziggy đã đề cập , ON CONFLICTchỉ hoạt động đối với các vi phạm ràng buộc duy nhất hoặc loại trừ thực tế . Hướng dẫn sử dụng:

    Điều ON CONFLICTkhoản tùy chọn chỉ định một hành động thay thế để nâng cao lỗi vi phạm ràng buộc hoặc loại trừ vi phạm duy nhất.

    Do đó, ON CONFLICT (b)không thể làm việc, không có ràng buộc ở đó. ON CONFLICT (pk_b)làm.

  3. Giống như @Ziggy cũng đề cập đến , nguồn tên bảng không nhìn thấy được trong UPDATEmột phần. Hướng dẫn sử dụng:

    Các SETWHEREcác điều khoản trong ON CONFLICT DO UPDATEcó quyền truy cập vào hàng hiện có sử dụng tên của bảng (hoặc một bí danh), và hàng đề xuất cho chèn bằng cách sử dụng đặc biệt excludedbảng .

    Nhấn mạnh đậm của tôi.

  4. Bạn cũng không thể sử dụng tên cột của bảng nguồn trong UPDATEphần. Nó phải là tên cột của hàng đích . Vì vậy, bạn thực sự muốn:

    SET    b = excluded.b

    Hướng dẫn một lần nữa:

    Lưu ý rằng các hiệu ứng của tất cả các BEFORE INSERTkích hoạt trên mỗi hàng được phản ánh trong các giá trị bị loại trừ, vì các hiệu ứng đó có thể đã góp phần khiến hàng bị loại khỏi chèn.


cảm ơn vì lời giải thích này, bây giờ tôi biết tại sao b = excluded.akhông thể làm việc, nó đã bị ẩn đi một chút trong tài liệu chính thức.
Patrick7

7

Khi thực hiện uperts trong PostgreSQL 9.5+, bạn phải tham khảo dữ liệu bị loại trừ (không thể chèn) bởi bí danh excluded. Ngoài ra, on conflicttùy chọn phải tham khảo khóa: (pk_b)chứ không phải (b). Ví dụ.

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

Để biết thêm thông tin tham khảo tài liệu chính thức hoặc giới thiệu dễ dàng này để upert .


Truy vấn này không hoạt động.
shx
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.