UPDATE 파트의 소스 테이블 값을 사용하는 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

답변:


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

'excluded'는 다음과 같은 인형에 대한 간단한 하나의 라이너입니다. 테이블에 삽입하거나 지속하려는 새로운 수신 데이터를 가리 킵니다.
user92674

8

PostgreSQL 9.5 이상에서 upsert를 수행 할 때 alias에 의해 제외 된 데이터 (삽입에 실패한 데이터)를 참조해야합니다 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.