ほとんどの行が削除され (ほとんどが重複)、テーブルが RAM に収まる場合は、次のルートを検討してください。
SELECT
生き残った行を一時テーブルに。
- FK 参照をサバイバーに再ルーティングする
DELETE
ベース テーブルのすべての行。
- 再
INSERT
生存者。
1a. 生き残った行を蒸留する
CREATE TEMP TABLE tmp AS
SELECT DISTINCT ON (login_name, password) *
FROM (
SELECT DISTINCT ON (email) *
FROM taccounts
ORDER BY email, last_login DESC
) sub
ORDER BY login_name, password, last_login DESC;
約DISTINCT ON
:
2 つの異なる条件の重複を識別するには、サブクエリを使用して 2 つのルールを順番に適用します。最初のステップでは、最新のアカウントを保持するlast_login
ため、これは「シリアル化可能」です。
結果を検査し、妥当性をテストします。
SELECT * FROM tmp;
一時テーブルは、セッションの終了時に自動的に削除されます。pgAdmin(使用しているようです)では、エディターウィンドウが開いている限り、セッションは存続します。
1b. 「重複」の更新された定義の代替クエリ
SELECT *
FROM taccounts t
WHERE NOT EXISTS (
SELECT FROM taccounts t1
WHERE ( NULLIF(t1.email, '') = t.email
OR (NULLIF(t1.login_name, ''), NULLIF(t1.password, '')) = (t.login_name, t.password))
AND (t1.last_login, t1.account_id) > (t.last_login, t.account_id)
);
これは、「重複」列のいずれかで同一として扱わないNULL
か、空の文字列 ( ) を扱いません。''
行式(t1.last_login, t1.account_id)
は、2 つの重複が同じ を共有する可能性に対処しlast_login
ます。この場合、大きいaccount_id
方が選択されます。これは PK であるため、一意です。
2a. すべての着信 FK を識別する方法
SELECT c.confrelid::regclass::text AS referenced_table
, c.conname AS fk_name
, pg_get_constraintdef(c.oid) AS fk_definition
FROM pg_attribute a
JOIN pg_constraint c ON (c.conrelid, c.conkey[1]) = (a.attrelid, a.attnum)
WHERE c.confrelid = 'taccounts'::regclass -- (schema-qualified) table name
AND c.contype = 'f'
ORDER BY 1, contype DESC;
外部キーの最初の列のみを構築します。それについての詳細:
またはDependents
、テーブルを選択した後、pgAdmin のオブジェクト ブラウザの右側のウィンドウでライダーを調べますtaccounts
。
2b. 新しいプライマリに再ルーティングします
参照しているテーブルがある場合taccounts
(への着信外部キー) 、重複を削除する前に、それらすべてのフィールドを更新する必要があります。
それらすべてを新しいプライマリ行に再ルーティングします。 taccounts
UPDATE referencing_tbl r
SET referencing_column = tmp.reference_column
FROM tmp
JOIN taccounts t1 USING (email)
WHERE r.referencing_column = t1.referencing_column
AND referencing_column IS DISTINCT FROM tmp.reference_column;
UPDATE referencing_tbl r
SET referencing_column = tmp.reference_column
FROM tmp
JOIN taccounts t2 USING (login_name, password)
WHERE r.referencing_column = t1.referencing_column
AND referencing_column IS DISTINCT FROM tmp.reference_column;
3. & 4. 殺しに行く
現在、重複は参照されなくなりました。殺しに行く。
ALTER TABLE taccounts DISABLE TRIGGER ALL;
DELETE FROM taccounts;
VACUUM taccounts;
INSERT INTO taccounts
SELECT * FROM tmp;
ALTER TABLE taccounts ENABLE TRIGGER ALL;
操作中はすべてのトリガーを無効にします。これにより、操作中の参照整合性のチェックが回避されます。トリガーを再度アクティブにすると、すべてがうまくいくはずです。上記のすべての着信FK を処理しました。同時書き込みアクセスがなく、すべての値が以前にそこにあったため、発信FK は健全であることが保証されます。