UPDATE部分のソーステーブルの値を使用するON CONFLICTを使用したUPSERT


17

与えられた:

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
アベリスト

do update set b = a;見つけることができません「」「B」表にしていない副問合せをそこに参照するには、しようとするためdo update set b = (select a from a);
Patrick7

回答:


24

複数の問題。
拡張されたセットアップ:

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一部。マニュアル:

    SETand WHERE句はON CONFLICT DO UPDATE、テーブルの名前(またはエイリアス)を使用して既存の行にアクセスし、特別なexcludedテーブルを使用して挿入が提案され行にアクセスします

    大胆な強調鉱山。

  4. また、ソーステーブルの列名をUPDATEパーツで使用することもできません。ターゲット行の列名でなければなりません。あなたは本当に欲しい:

    SET    b = excluded.b

    もう一度マニュアル:

    すべての行ごとのBEFORE INSERTトリガーの効果は、除外された値に反映されることに注意してください。これらの効果は、挿入から除外される行に寄与している可能性があるためです。


この説明のおかげで、今ではなぜ機能しb = excluded.aないのかがわかりました。公式Docuには少し隠されていました。
パトリック

7

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;

詳細については、公式ドキュメントまたはこのupsertの簡単な紹介を参照してください。


このクエリは機能しませ
-shx
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.