私はこれをトランザクションで達成する方法を見つけることができないようです(またはそうではありません)
私が達成する必要があるのは標準ではないため、解決策を見つけるのが困難です。
テーブル内の古いレコードを新しいレコードと「交換」するようにデータ移行ツールをコーディングする必要がありますが、次の要件/制約があります。
したがって、私の理想的なソリューションは、主キーをブルートスワップすることです...
問題は、postgresqlの2つのレコード間で主キーをどのように交換できるかです。重複キーの例外で失敗しないアプローチ、つまりトランザクションの更新の「検証」を実行するアプローチを見つけるのが困難です。
私が試してみました
UPDATE table
SET id = (CASE id WHEN 1 THEN 2 WHEN 2 THEN 1 ELSE id END)
UPDATE table
SET id = CASE id WHEN 1 THEN 2 WHEN 2 THEN 1 END
WHERE id IN (1, 2);
どちらも重複キー制約で失敗する
PostgreSQL 11.6を使用しています
以下のニースの人々からの入力のおかげで、数値の主キーの一括更新のソリューション:
-- disable foreign key constraint validation
BEGIN;
SET session_replication_role='replica';
-- update the pairs of ids to their negative counterparts
WITH query AS ('query to get pairs of ids to swap')
UPDATE table
SET id = -id
WHERE id in (query.id1, query.id2);
-- update the pairs of negated ids to their positive counterparts swapped
WITH query AS ('query to get pairs of ids to swap')
UPDATE table
SET id = CASE id WHEN query.id1 THEN -query.id2
WHEN query.id2 THEN -query.id1
END
WHERE id in (query.id1, query.id2);
-- enable foreign key constraint validation
SET session_replication_role='original';
COMMIT;
遅延制約を使用できます。そのためには、主キーを削除して再作成する必要があります。
CREATE UNIQUE INDEX mytable_primkey ON mytable (id);
ALTER TABLE mytable DROP CONSTRAINT mytable_pkey;
ALTER TABLE mytable ADD PRIMARY KEY USING INDEX mytable_primkey
DEFERRABLE INITIALLY DEFERRED;
更新自体は、次のように実行できます。
UPDATE mytable SET id = 3 - id WHERE id IN (1, 2);
ここでは1と2が例として使用されていますが、これは任意の数値で実行できます。
延期された主キーを追加するために必要なダウンタイムが許されない場合は、次のようなもう1つの更新でそれを行うことができます。
BEGIN;
UPDATE mytable SET id = 0 WHERE id = 1;
UPDATE mytable SET id = 1 WHERE id = 2;
UPDATE mytable SET id = 2 WHERE id = 0;
COMMIT;
ここで、0はid
の値として使用されない任意の値です。
これが可能であると私が知る唯一の方法は、遅延制約を使用することです。
主キーを削除する必要があります。
alter table x drop constraint x_pkey;
そして延期可能として再びそれを追加します:
alter table x add primary key (id) deferrable initially immediate;
更新を実行する前に、制約を延期できます。
set constraints x_pkey deferred;
次に、更新とcommit
を実行します。
https://dbfiddle.uk/?rdbms=postgres_12&fiddle=469e5168c84bdbb8361426d4458bcf88
もちろん、このテーブルを参照する他のテーブルがある場合は、外部キーも削除して再作成する必要があります。