web-dev-qa-db-ja.com

PostgreSQLで外部キーを持つ行を削除します

外部キーを含む行を削除したいのですが、次のようなことをしようとすると:

DELETE FROM osoby WHERE id_osoby='1'

私はこの声明を受け取ります:

エラー:テーブル "osoby"の更新または削除は、テーブル "kontakty"の外部キー制約 "kontakty_ibfk_1"に違反しています詳細:キー(id_osoby)=(1)は、まだテーブル "kontakty"から参照されています。

これらの行を削除するにはどうすればよいですか?

55
Michal Loksik

これを自動化するには、ON DELETE CASCADEを使用して外部キー制約を定義できます。
引用 外部キー制約のマニュアル

CASCADEは、参照されている行が削除されたときに、それを参照している行も自動的に削除されることを指定します。

現在のFK定義を次のように検索します。

SELECT pg_get_constraintdef(oid) AS constraint_def
FROM   pg_constraint
WHERE  conrelid = 'public.kontakty'::regclass  -- assuming pubic schema
AND    conname = 'kontakty_ibfk_1';

次に、次のようなステートメントでON DELETE ...部分をON DELETE CASCADEに追加または変更します(他のすべてをそのまま保持)。

ALTER TABLE kontakty
   DROP CONSTRAINT kontakty_ibfk_1
 , ADD  CONSTRAINT kontakty_ibfk_1
   FOREIGN KEY (id_osoby) REFERENCES osoby (id_osoby) ON DELETE CASCADE;

ALTER CONSTRAINT構文がないため、単一のALTER TABLEステートメントで制約を削除して再作成します。これにより、同時書き込みアクセスの競合状態を回避できます。

もちろん、そうするための特権が必要です。操作は、ACCESS EXCLUSIVEテーブルのロックkontaktyと、_SHARE ROW EXCLUSIVEテーブルのロックosobyを取ります。

テーブルをALTERできない場合、手動(1回)またはトリガーBEFORE DELETE(毎回)で削除することが残りのオプションです。

66

外部キーがまだ別のテーブルを参照している場合は、外部キーを削除できません。最初に参照を削除します

delete from kontakty
where id_osoby = 1;

DELETE FROM osoby 
WHERE id_osoby = 1;
31
juergen d

これを一般的な解決策としてお勧めするべきではありませんが、本番環境またはアクティブに使用されていないデータベースの行を1回限り削除する場合は、問題のテーブルのトリガーを一時的に無効にできる場合があります。

私の場合、開発モードで、外部キーを介して相互に参照するテーブルがいくつかあります。したがって、コンテンツを削除することは、あるテーブルからすべての行を他のテーブルよりも前に削除するほど簡単ではありません。だから、私にとっては、次のようにコンテンツを削除してもうまくいきました:

ALTER TABLE table1 DISABLE TRIGGER ALL;
ALTER TABLE table2 DISABLE TRIGGER ALL;
DELETE FROM table1;
DELETE FROM table2;
ALTER TABLE table1 ENABLE TRIGGER ALL;
ALTER TABLE table2 ENABLE TRIGGER ALL;

もちろん、データベースの整合性が損なわれないように注意して、必要に応じてWHERE句を追加できる必要があります。

http://www.openscope.net/2012/08/23/subverting-foreign-key-constraints-in-postgres-or-mysql/ に関連する良い議論があります。

16
Andrew Basile

この質問が尋ねられてからしばらく経ちましたが、希望は助けになります。 db構造を変更または変更できないため、これを行うことができます。 postgresql docs に従います。

TRUNCATE-テーブルまたはテーブルのセットを空にします。

TRUNCATE [ TABLE ] [ ONLY ] name [ * ] [, ... ]
    [ RESTART IDENTITY | CONTINUE IDENTITY ] [ CASCADE | RESTRICT ]

説明

TRUNCATEは、テーブルのセットからすべての行をすばやく削除します。各テーブルでの非修飾DELETEと同じ効果がありますが、実際にはテーブルをスキャンしないため、高速です。さらに、後続のVACUUM操作を必要とせずに、すぐにディスク領域を再利用します。これは、大きなテーブルで最も役立ちます。


テーブルothertableを切り捨て、外部キー制約を介してothertableを参照するテーブルにカスケードします。

TRUNCATE othertable CASCADE;

同じで、関連するシーケンスジェネレータもリセットします。

TRUNCATE bigtable, fattable RESTART IDENTITY;

関連するシーケンスジェネレータを切り捨ててリセットします。

TRUNCATE revinfo RESTART IDENTITY CASCADE ;
10
OJVM

テーブルkontaktyには、削除するosobyの行を参照する行があることを意味します。最初にその行を削除するか、テーブル間のリレーションに対してカスケード削除を設定してください。

ポウォゼニア!

6
zibi