web-dev-qa-db-ja.com

複数のテーブルからデータを削除する方法は?

私はこれらのテーブルを持っています:

出来事     (evt_id、evt_code、reg_id)
 
大きさ (mag_id、evt_id、value)
 
痕跡     (trace_id、pt_id)
 
ポイント     (pt_id、evt_id)

evt_id=1139に関連するすべてのテーブルからすべての行を削除したい。
どうすればいいのですか?

22
user1202766

スキーマを制御できる場合は、スキーマで カスケード削除 を使用します。

記事から(あなたの例のために翻訳されたより適切な部分)

CREATE TABLE point
(
    pt_id integer PRIMARY KEY,
    evt_id integer REFERENCES event ON DELETE CASCADE
)

カスケードを設定している場合、メインイベントテーブルから削除するだけで、他のすべてのテーブルは自動的にクリーンアップされます

それ以外の場合は、最初にすべての参照を削除してから、メインテーブルを削除する必要があります。データの一貫性を保つために、1つのトランザクションでこれを行う必要があります

BEGIN;
DELETE FROM trace WHERE EXISTS 
    (SELECT 1 FROM point WHERE evt_id = 1139 AND trace.pt_id = point.pt_id);
DELETE FROM point where evt_id = 1139;
DELETE FROM magnitude where evt_id = 1139;
DELETE FROM event where evt_id = 1139;
COMMIT;
19
Justin Pihony

あなたの質問の重要な要素は、テーブルtraceからの削除だけです。 trace.pt_idpoint.pt_idを参照していると想定しても安全だと思いますか?

foreign keyをON DELETE CASCADE で定義し、テーブルtraceを忘れます(既に @kevin )によって指摘された、または手動で行に依存することに注意する必要があります。

PostgreSQL9.1以降、 data-modifying CTEs

BEGIN;

WITH x AS (
    DELETE FROM point WHERE evt_id = 1139
    RETURNING pt_id
    )
DELETE FROM trace
USING x
WHERE trace.pt_id = x.pt_id;

DELETE FROM magnitude WHERE evt_id = 1139;

DELETE FROM event WHERE evt_id = 1139;

COMMIT;

DELETE FROM pointRETURNING句 は、影響を受けるすべてのpt_idを返します。これらは、traceからすべての対応する行を削除するために使用されます。

concurrencyが問題であるかどうかは言及しませんでした。ある場合、およびevt_id = 1139の行が別のテーブルから既に削除されている間に別のテーブルに存在する削除の間の短い時間ウィンドウで起こり得る結果を避けたい場合は、すべてをtransaction
それが気にならない場合は、BEGINCOMMITを無視してください。

deadlocksを回避するには、常に同じシーケンスのdeleteステートメントを(すべての同時トランザクションで)使用します。これにより、1つのトランザクションが1つのテーブルで削除を開始し、別のトランザクションが別のテーブルで削除されてから、それぞれが他のテーブルを待機するという状況を回避できます。

14

削除する行を階層として想定できる場合、ON DELETE CASCADE句を使用して関係のFOREIGN KEY制約を定義できます。上部の行を削除すると、カスケードしてすべて削除されます。

http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#DDL-CONSTRAINTS-FK

5
kgrittn