Postgres の 2 つの行の ID を変更して、それらを切り替えたいと考えています。これらはすでに外部キーとして定義されているため、3 番目の番号を使用して切り替えを行うことはできません。
1 つの SQL クエリまたはトランザクションでこれを行うにはどうすればよいですか?
例:
UPDATE mytable SET id=2 WHERE ID=1;
UPDATE mytable SET id=1 WHERE ID=2
Postgres の 2 つの行の ID を変更して、それらを切り替えたいと考えています。これらはすでに外部キーとして定義されているため、3 番目の番号を使用して切り替えを行うことはできません。
1 つの SQL クエリまたはトランザクションでこれを行うにはどうすればよいですか?
例:
UPDATE mytable SET id=2 WHERE ID=1;
UPDATE mytable SET id=1 WHERE ID=2
id
あなたは外部キーについて言及していますが、外部キー制約の参照列なのか参照列なのかは不明のままです。
id
が参照列である場合は、fk 制約を定義するだけですON UPDATE CASCADE
。その後、好きなだけ変更できますid
。変更は、依存する列にカスケードされます。
id
が参照列である場合(および他の外部キー制約がそれを指していない場合)、PostgreSQL 9.0以降、別のより高速な方法があります。遅延可能な主キーまたは一意のキーを使用できます。次のデモを検討してください。
別のテーブルから外部キーid
制約を使用して参照する場合は、これを使用できないことに注意してください。ここでマニュアルを引用します:
参照される列は、参照されるテーブル内の遅延不可能な一意または主キー制約の列である必要があります。
テストベッド:
CREATE TEMP TABLE t
( id integer
,txt text
,CONSTRAINT t_pkey PRIMARY KEY (id) DEFERRABLE INITIALLY DEFERRED
);
INSERT INTO t VALUES
(1, 'one')
,(2, 'two');
アップデート:
UPDATE t
SET id = t_old.id
FROM t t_old
WHERE (t.id, t_old.id) IN ((1,2), (2,1));
結果:
SELECT * FROM t;
id | txt
---+-----
2 | one
1 | two
制約を宣言して、同じトランザクションDEFERRABLE INITIALLY IMMEDIATE
で使用することもできます。SET CONSTRAINTS ... DEFERRED
マニュアルの詳細については、必ずお読みください。
DEFERRABLE INITIALLY IMMEDIATE
and noでも動作するようSET CONSTRAINTS
です。私はそれについて質問を投稿しました。
次のようなことを試しましたか:
BEGIN;
CREATE TEMP TABLE updates ON COMMIT DROP AS
SELECT column1::int oldid, column2::int newid
FROM ( VALUES (1, 2), (2, 1) ) foo;
UPDATE mytable
FROM updates
SET id = newid
WHERE id = oldid;
--COMMIT;
ROLLBACK;
もちろん、ロールバックはコメントアウトされ、準備ができたらコミットされます。
begin;
alter table mytable drop constraint_name;
UPDATE mytable SET id=-1 WHERE ID=1;
UPDATE mytable SET id=1 WHERE ID=2;
UPDATE mytable SET id=2 WHERE ID=-1;
alter table mytable add table_constraint;
commit;