質問は古いですが、ここで提案されていることを適用しようとした後、dba.SEの絶望的なユーザーから新しい質問がありました。 詳細と説明がありますで答えを見つけてください :
現在受け入れられている回答 ほとんどの場合失敗します 。
-
通常、
PRIMARY KEY
があります またはUNIQUE
id
の制約NOT DEFERRABLE
である列 デフォルトでは。 (OPはreferences and constraints
に言及しています 。)このような制約は各行の後にチェックされるため、固有の違反が発生する可能性があります。 試行エラー。詳細: -
通常、元の行の順序を保持する必要があります ギャップを埋めながら。ただし、行が更新される順序は任意です。 、任意の数になります。示されている例では、物理ストレージが目的の順序(ほんの少し前に目的の順序で行が挿入されている)と一致しているため、元のシーケンスが保持されているようです。これは、実際のアプリケーションではほとんど発生せず、完全に信頼性がありません。
問題は最初に思われるよりも複雑です。 1つ PK / UNIQUE制約(および関連するFK制約)を一時的に削除する余裕がある場合の解決策(とりわけ):
BEGIN;
LOCK tbl;
-- remove all FK constraints to the column
ALTER TABLE tbl DROP CONSTRAINT tbl_pkey; -- remove PK
-- for the simple case without FK references - or see below:
UPDATE tbl t -- intermediate unique violations are ignored now
SET id = t1.new_id
FROM (SELECT id, row_number() OVER (ORDER BY id) AS new_id FROM tbl) t1
WHERE t.id = t1.id;
-- Update referencing value in FK columns at the same time (if any)
SELECT setval('tbl_id_seq', max(id)) FROM tbl; -- reset sequence
ALTER TABLE tbl ADD CONSTRAINT tbl_pkey PRIMARY KEY(id); -- add PK back
-- add all FK constraints to the column back
COMMIT;
これも すべての行のPK(およびFK)制約をチェックすることは、制約を削除して再度追加するよりもはるかにコストがかかるため、大きなテーブルの場合は高速になります。
tbl.id
を参照する他のテーブルにFK列がある場合 、データ変更CTE> それらすべてを更新します。
テーブルの例fk_tbl
およびFK列fk_id
:
WITH u1 AS (
UPDATE tbl t
SET id = t1.new_id
FROM (SELECT id, row_number() OVER (ORDER BY id) AS new_id FROM tbl) t1
WHERE t.id = t1.id
RETURNING t.id, t1.new_id -- return old and new ID
)
UPDATE fk_tbl f
SET fk_id = u1.new_id -- set to new ID
FROM u1
WHERE f.fk_id = u1.id; -- match on old ID
詳細については、dba.SEの参照回答 をご覧ください。 。