[解決済み] ON CONFLICT節で複数のconflict_targetを使用する。
質問
テーブルに2つのカラムがあります
col1
,
col2
のように、どちらも一意にインデックスされています(col1も一意であり、col2も一意です)。
私はこのテーブルに挿入する必要がある、使用
ON CONFLICT
構文を使って、他のカラムを更新する必要があります。
conflict_target
節で両方のカラムを使用することはできません。
動作します。
INSERT INTO table
...
ON CONFLICT ( col1 )
DO UPDATE
SET
-- update needed columns here
しかし、複数のカラムに対してこれを行うには、以下のような感じです。
...
ON CONFLICT ( col1, col2 )
DO UPDATE
SET
....
どのように解決するのですか?
サンプルテーブルとデータ
CREATE TABLE dupes(col1 int primary key, col2 int, col3 text,
CONSTRAINT col2_unique UNIQUE (col2)
);
INSERT INTO dupes values(1,1,'a'),(2,2,'b');
問題の再現
INSERT INTO dupes values(3,2,'c')
ON CONFLICT (col1) DO UPDATE SET col3 = 'c', col2 = 2
これをQ1と呼ぶことにしましょう。その結果は
ERROR: duplicate key value violates unique constraint "col2_unique"
DETAIL: Key (col2)=(2) already exists.
が表示されるのは ドキュメント が言う
<ブロッククオートconflict_targetはユニークインデックス推論を行うことができます。推論を行う場合 推論を行う場合、1つ以上のindex_column_nameカラムやindex_expression式、そしてオプションのindex_predicateから構成されます。 index_expression式、およびオプションのindex_predicateから成ります。すべての テーブル名のユニークインデックスのうち、順序に関係なく テーブル名のユニークインデックスのうち、conflict_targetで指定されたカラムや式を正確に含むものが、アービターインデックスとして推論されます。 (アービターインデックスとして推論(選択)されます。index_predicateが指定された場合、そのindex_predicateは以下のようになります。 は、推論のためのさらなる要件として、アービターインデックスを満たさなければならない。
これは、以下の問い合わせが動作するはずだという印象を与えますが、実際にはcol1とcol2に対して一緒にユニークなインデックスを必要とするため、動作しないのです。しかし、そのようなインデックスは、OPの要求の1つである、col1とcol2が個々に一意であることを保証しません。
INSERT INTO dupes values(3,2,'c')
ON CONFLICT (col1,col2) DO UPDATE SET col3 = 'c', col2 = 2
このクエリをQ2と呼ぶことにしましょう(これは構文エラーで失敗します)。
なぜですか?
Postgresqlがこのような動作をするのは、2番目のカラムで競合が発生したときに何が起こるべきかがうまく定義されていないためです。いくつかの可能性があります。例えば、上記のQ1クエリでは、postgresqlは以下のように更新すべきです。
col1
で競合が発生した場合
col2
? しかし、それが別の衝突につながるとしたらどうでしょう。
col1
で別の衝突が発生した場合、postgresqlはどのように対処するのでしょうか?
解決策
解決策としては、ON CONFLICT と 昔ながらのUPSERT .
CREATE OR REPLACE FUNCTION merge_db(key1 INT, key2 INT, data TEXT) RETURNS VOID AS
$$
BEGIN
LOOP
-- first try to update the key
UPDATE dupes SET col3 = data WHERE col1 = key1 and col2 = key2;
IF found THEN
RETURN;
END IF;
-- not there, so try to insert the key
-- if someone else inserts the same key concurrently, or key2
-- already exists in col2,
-- we could get a unique-key failure
BEGIN
INSERT INTO dupes VALUES (key1, key2, data) ON CONFLICT (col1) DO UPDATE SET col3 = data;
RETURN;
EXCEPTION WHEN unique_violation THEN
BEGIN
INSERT INTO dupes VALUES (key1, key2, data) ON CONFLICT (col2) DO UPDATE SET col3 = data;
RETURN;
EXCEPTION WHEN unique_violation THEN
-- Do nothing, and loop to try the UPDATE again.
END;
END;
END LOOP;
END;
$$
LANGUAGE plpgsql;
このストアド関数のロジックを変更して、カラムを正確に更新するようにする必要があります。次のように呼び出してください。
SELECT merge_db(3,2,'c');
SELECT merge_db(1,2,'d');
関連
-
PostgreSQLはバッチ実行のためにSQLをファイルに実装しています。
-
PostgreSQLで時間指定タスクを実装する4つの方法
-
[解決済み] psql: FATAL: データベース "<user>" が存在しない
-
[解決済み] PostgreSQLで重複して更新された場合の挿入?
-
[解決済み] SQLite - UPSERT *not* INSERT or REPLACE
-
[解決済み】Postgresqlで、2つのカラムの組み合わせで一意性を強制する。
-
[解決済み] PostgreSQLのINSERT ON CONFLICT UPDATE(upsert)は除外された値をすべて使用します。
-
[解決済み] enumが持ちうるすべての値を取得するSQLクエリ
-
[解決済み] PostgreSQL公式Dockerイメージの設定ファイルをカスタマイズする方法とは?
-
[解決済み] Postgresql。条件付き一意性制約
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Centos環境でのPostgresqlのインストールと設定、環境変数の設定Tips
-
postgresql いくつかのメソッドは、要約の重複するデータを削除する
-
postgreSQLのクエリ結果に自己インクリメントシーケンス演算が追加されました。
-
PostgreSqlのhash_code関数の使用法
-
Postgresql+Springboot ymlの基本的な使い方
-
[解決済み] psqlでデータベースを切り替えるには?
-
[解決済み] PostgresでInsert文のUUIDを生成する?
-
[解決済み] psqlの代替出力フォーマット
-
[解決済み] PostgreSQL用GUIツール【終了】のお知らせ
-
[解決済み] PostgreSQL公式Dockerイメージの設定ファイルをカスタマイズする方法とは?