単一のSQLステートメントを使用すると、これをはるかに効率的に行うことができます。 データ変更CTE 。
WITH plan AS (
SELECT *
FROM (
SELECT recid, min(recid) OVER (PARTITION BY cdesc) AS master_recid
FROM cpt
) sub
WHERE recid <> master_recid -- ... <> self
)
, upd_lab AS (
UPDATE lab l
SET cpt_recid = p.master_recid -- link to master recid ...
FROM plan p
WHERE l.cpt_recid = p.recid
)
DELETE FROM cpt c
USING plan p
WHERE c.recid = p.recid
RETURNING c.recid;
db <> fiddle こちら
(11ページ)
SQL Fiddle
(9.6ページ)
これは多くである必要があります より速く、よりクリーンに。ループは比較的高価であり、例外処理は比較的さらに高価です。
さらに重要なのは、lab
での参照です。 cpt
のそれぞれのマスター行にリダイレクトされます 自動的に、これは元のコードにはまだ含まれていませんでした。したがって、すべての重複を一度に削除できます 。
必要に応じて、これをplpgsqlまたはSQL関数でラップすることもできます。
説明
-
最初のCTEで
plan
、同じcdesc
を使用して各パーティションのマスター行を識別します 。あなたの場合、最小のrecid
を持つ行 。 -
2番目のCTEで
upd_lab
重複を参照するすべての行をcpt
のマスター行にリダイレクトします 。 -
最後に、重複を削除します。これにより、依存する行が残りのマスター行に実質的に同時にリンクされるため、例外が発生することはありません。
ON DELETE RESTRICT
すべてのCTEとステートメントのメインクエリ 基になるテーブルの同じスナップショットを実質的に同時に操作します 。基になるテーブルに対する互いの影響はわかりません:
ON DELETE RESTRICT
を使用したFK制約が予想される場合があります 例外を発生させる理由は、[ドキュメントごと] [3]:
ただし、上記のステートメントは単一のコマンドです そして、[再びマニュアル] [3]:
大胆な強調鉱山。制限の少ないデフォルトのON DELETE NO ACTION
で機能します もちろんです。
ただし、同じテーブルへの同時トランザクションの書き込みには注意してください。ただし、これは一般的な考慮事項であり、このタスクに固有のものではありません。
UNIQUE
には例外が適用されます およびPRIMARY KEY
制約がありますが、これは関係ありません ケース: