2016-09-29 574 views
3

FROMステートメントで複数のソースを使用しようとすると、Postgres 9.5のON CONFLICT DO UPDATEに問題があります。制限値が重複しているUpsertエラー(On Conflict Do Update)

INSERT INTO new.bookmonographs (citavi_id, abstract, createdon, edition, title, year) 
SELECT "ID", "Abstract", "CreatedOn"::timestamp, "Edition", "Title", "Year" 
FROM old."Reference" 
WHERE old."Reference"."ReferenceType" = 'Book' 
    AND old."Reference"."Year" IS NOT NULL 
    AND old."Reference"."Title" IS NOT NULL 
ON CONFLICT (citavi_id) DO UPDATE 
    SET (abstract, createdon, edition, title, year) = (excluded.abstract, excluded.createdon, excluded.edition, excluded.title, excluded.year) 
; 

不良コード:作業コードの

INSERT INTO new.bookmonographs (citavi_id, abstract, createdon, edition, title, year) 
SELECT "ID", "Abstract", "CreatedOn"::timestamp, "Edition", "Title", "Year" 
FROM old."Reference", old."ReferenceAuthor" 
WHERE old."Reference"."ReferenceType" = 'Book' 
    AND old."Reference"."Year" IS NOT NULL 
    AND old."Reference"."Title" IS NOT NULL 
    AND old."ReferenceAuthor"."ReferenceID" = old."Reference"."ID" 
    --Year, Title and Author must be present in the data, otherwise the entry is deemed useless, hence won't be included 
ON CONFLICT (citavi_id) DO UPDATE 
    SET (abstract, createdon, edition, title, year) = (excluded.abstract, excluded.createdon, excluded.edition, excluded.title, excluded.year) 
; 

私は、文とその確かエントリのみを作るための1つの以上のステートメントから追加のソースを追加しましたタイトル、年、著者が新しいデータベースに挿入されます。 (古い場合は "Reference"。 "ID"は "ReferenceAuthor"として "ReferenceID"として存在し、その後は作成者が存在します。)追加のWHERE文がなくても、クエリに誤りがあります。 SELECTで指定した列はold."Reference"にのみ存在し、old."ReferenceAuthor"には存在しません。

ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time HINT: Ensure that no rows proposed for insertion within the same command have duplicate constrained values. ********** Error **********

ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time SQL state: 21000 Hint: Ensure that no rows proposed for insertion within the same command have duplicate constrained values.

私が間違っているかわからない、またはなぜ:

CONSTRAINT bookmonographs_pk PRIMARY KEY (bookmonographsid), 
CONSTRAINT bookmonographs_bookseries FOREIGN KEY (bookseriesid) 
     REFERENCES new.bookseries (bookseriesid) MATCH SIMPLE 
     ON UPDATE NO ACTION ON DELETE NO ACTION, 
CONSTRAINT bookmonographs_citaviid_unique UNIQUE (citavi_id) 

エラーPSQLはスロー: 現在old."ReferenceAuthor"old."Reference"がUNIQUE制約を持っていない、bookmonographsためuniqe制約がありますヒントは、重複した制約値を指します。

答えて

6

問題が明らかにいくつかのエントリは、複数の著者を持っていることに起因します。したがって、あなたが書いた選択クエリの内部結合は、同じエントリの複数の行を返し、INSERT ... ON CONFLICTはそれを好まないのです。フィルタリングにはReferenceAuthorテーブルのみを使用するので、相関サブクエリでexistsを実行して、そのテーブルを使用して作成者がないエントリのみをフィルタリングするようにクエリを書き換えることができます。ここに方法は次のとおりです。残念ながら、これは動作しません

INSERT INTO new.bookmonographs (citavi_id, abstract, createdon, edition, title, year) 
SELECT "ID", "Abstract", "CreatedOn"::timestamp, "Edition", "Title", "Year" 
FROM old."Reference" 
WHERE old."Reference"."ReferenceType" = 'Book' 
    AND old."Reference"."Year" IS NOT NULL 
    AND old."Reference"."Title" IS NOT NULL 
    AND exists(SELECT FROM old."ReferenceAuthor" WHERE old."ReferenceAuthor"."ReferenceID" = old."Reference"."ID") 
    --Year, Title and Author must be present in the data, otherwise the entry is deemed useless, hence won't be included 
ON CONFLICT (citavi_id) DO UPDATE 
    SET (abstract, createdon, edition, title, year) = (excluded.abstract, excluded.createdon, excluded.edition, excluded.title, excluded.year) 
; 
+0

注:*通常のケース*更新では、 "ターゲットごとの複数の更新"は無視されます(最終的な結果はソースタプルのランダムな順序に依存します)。 ON CONFLICTの場合、ターゲットタプルごとに複数のソースタプルが再帰的/カスケードのコンフリクトを引き起こすか、またはランダムな順序の問題が発生するか、または失敗します(OQの場合と同様)。 – joop

+0

魅力的な作品です、ありがとうございました。エラーの原因を特定するためのあなたの思考プロセスは何でしたか?それともこの種の問題を経験したことでしょうか? – Telefonmann

+0

@Telefonmann私はすでにこの制限を認識していましたが、エラーメッセージもかなり明確でした。 – redneb

1

は、2つのソーステーブルを結合するために、明示的なINNER JOINを使用します。

INSERT INTO new.bookmonographs (citavi_id, abstract, createdon, edition, title, year) 
SELECT "ID", "Abstract", "CreatedOn"::timestamp, "Edition", "Title", "Year" 
FROM old."Reference" 
INNER JOIN old."ReferenceAuthor"          -- explicit join 
    ON old."ReferenceAuthor"."ReferenceID" = old."Reference"."ID"  -- ON condition 
WHERE old."Reference"."ReferenceType" = 'Book' AND 
     old."Reference"."Year" IS NOT NULL  AND 
     old."Reference"."Title" IS NOT NULL 
ON CONFLICT (citavi_id) DO UPDATE 
SET (abstract, createdon, edition, title, year) = 
    (excluded.abstract, excluded.createdon, excluded.edition, excluded.title, 
    excluded.year) 
+0

、PSQLは、同じエラーがスローされます。 rednebの解決策は動作します。 – Telefonmann

関連する問題