更新されたバージョンが主キー制約に違反しない場合、postgresデータベースの行を更新したいと思います。もしそうなら、私は行をそのまま残したいと思います。
次のようなクエリを実行した場合、テーブルにcol1, col2, col3
の主キーがあると仮定します。
UPDATE table SET (col1, col2) = ('AAA', 'BBB')
WHERE col1='AAB' AND col2='BBA';
2つのエントリが存在する場合、クエリは失敗し、重複キーエラーが発生します。
'AAA', 'BBB', 'CCC'
'AAB', 'BBA', 'CCC'
つまり、col3
は、既存の行と更新される行で同じです。
行をINSERT
ingしている場合はON CONFLICT DO NOTHING
を使用しますが、UPDATE
の実装を見つけることができません。同等のものはありますか?
私の知る限り、そのような同等のものはありません。
Postgresqlデータベースに接続するアプリケーションを開発しているとしましょう。質問のコンテキストで、覚えておくべきことがいくつかあります。
on conflict
_(更新またはなし)の代替選択肢があるため、ユーザーが決定できる構文を使用することは理にかなっています。ON CONFLICT ...
_は、主キーフィールドを更新するためのものではありません。実際は正反対です。単一のレコード内のすべてのフィールド主キーからのものを除くを更新することを目的としています。その点については、クエリが失敗するために主キーの競合は必要なかったことに注意してください
「便利な」_ON UPDATE NO ACTION
_外部キーを持つ1つのレコードも失敗します(これは、_ON UPDATE CASCADE
_ ...で50のテーブルの10M +レコードを更新するよりも優れています)。ところで、Oracleには_ON UPDATE CASCADE
_句さえないことをご存知ですか?その理由は何だと思いますか?
そのような状況で何ができる/すべきでないでしょうか?
UNIQUE
制約に対しても有効ですが、主キーを更新しないでください。CHECK
またはEXCLUSION
)に拡張する場合、もう一度、回避するためだけに、エラーなしで必要な追加コードを実際に入力しますか?エラーコード?current transaction is aborted, commands ignored until end of transaction block
_を取得し始めます。どうぞ:
_BEGIN;
SAVEPOINT MySavepoint;
UPDATE mytable set myuniquefield = 3; /*2+ records are going to be updated */
rollback to savepoint MySavepoint;
/*Insert Some more queries here*/
COMMIT;
_
WHERE NOT EXISTS
句を使用して相関サブクエリを使用すると、次のように、更新によって重複が生成されないようにすることができます。
UPDATE mytable t
SET (col1, col2) = ('AAA', 'BBB')
WHERE t.col1 = 'AAB' and t.col2 = 'BBA'
AND NOT EXISTS (
SELECT 1 FROM mytable WHERE col1 = 'AAA' AND col2 = 'BBB' AND col3 = t.col3
);
this db fiddle でテストされています。
[〜#〜]編集[〜#〜]
Roman Konovalがコメントしたように、UPDATE
の実行中に同時トランザクションが同じキーを挿入すると、重複キーエラーが引き続き発生することに注意してください。これは、テーブルの主キーを更新することは良い習慣ではないことを正確に示しています(この問題の詳細については、@ Lauからの以下の回答を参照してください)。