web-dev-qa-db-ja.com

PostgreSQL:外部キー/削除キーのカスケード

次のような2つのテーブルがあります。

DROP   TABLE  IF EXISTS schemas.book;
DROP   TABLE  IF EXISTS schemas.category;
DROP   SCHEMA IF EXISTS schemas;
CREATE SCHEMA schemas;

CREATE TABLE schemas.category (
  id          BIGSERIAL PRIMARY KEY,
  name        VARCHAR   NOT NULL,
  UNIQUE(name)
);

CREATE TABLE schemas.book (
  id          BIGSERIAL PRIMARY KEY,
  published   DATE      NOT NULL,
  category_id BIGINT    NOT NULL REFERENCES schemas.category ON DELETE CASCADE ON UPDATE CASCADE,
  author      VARCHAR   NOT NULL,
  name        VARCHAR   NOT NULL,
  UNIQUE(published, author, name),
  FOREIGN KEY(category_id) REFERENCES schemas.category (id)
);

したがって、ロジックは単純です。ユーザーがカテゴリxの下のすべての本を削除した後、xが猫から削除されます。上記の方法を試してみましたが、機能しません

25
juk

カスケード削除の外部キーは、親テーブルのレコードが削除されると、子テーブルの対応するレコードが自動的に削除されることを意味します。これはカスケード削除と呼ばれます。

逆の言い方をすると、これは子テーブルから削除すると、レコードが親テーブルから削除されるということではありません。

UPDATE 1:

ON DELETE CASCADEオプションは、親テーブルで対応する行が削除されたときに、子テーブルで行を削除するかどうかを指定します。カスケード削除を指定しない場合、データベースサーバーのデフォルトの動作により、他のテーブルが参照しているテーブルのデータを削除できません。

このオプションを指定すると、後で親テーブルの行を削除するときに、データベースサーバーは子テーブルのその行(外部キー)に関連付けられている行も削除します。カスケード削除機能の主な利点は、削除アクションの実行に必要なSQLステートメントの量を削減できることです。

つまり、子テーブルではなく親テーブルから行を削除するとどうなるかがすべてです

そのため、ユーザーがCATsテーブルからエントリを削除すると、booksテーブルから行が削除されます。 :)

これがあなたを助けることを願っています:)

66
Mari

PostgreSQLからの抜粋ドキュメント

削除の制限とカスケードは、最も一般的な2つのオプションです。 [...] CASCADEは、参照された行が削除されたときに、それを参照している行も自動的に削除されることを指定します。

これは、書籍で参照されているカテゴリを削除すると、参照元の書籍もON DELETE CASCADEで削除されることを意味します。

CREATE SCHEMA shire;

CREATE TABLE shire.clans (
    id serial PRIMARY KEY,
    clan varchar
);

CREATE TABLE shire.hobbits (
    id serial PRIMARY KEY,
    hobbit varchar,
    clan_id integer REFERENCES shire.clans (id) ON DELETE CASCADE
);

DELETE FROMクランはCASCADEによってホビットにREFERENCESします。

sauron@mordor> psql
sauron=# SELECT * FROM shire.clans;
 id |    clan    
----+------------
  1 | Baggins
  2 | Gamgi
(2 rows)

sauron=# SELECT * FROM shire.hobbits;
 id |  hobbit  | clan_id 
----+----------+---------
  1 | Bilbo    |       1
  2 | Frodo    |       1
  3 | Samwise  |       2
(3 rows)

sauron=# DELETE FROM shire.clans WHERE id = 1 RETURNING *;
 id |  clan   
----+---------
  1 | Baggins
(1 row)

DELETE 1
sauron=# SELECT * FROM shire.hobbits;
 id |  hobbit  | clan_id 
----+----------+---------
  3 | Samwise  |       2
(1 row)

本当に反対のことが必要な場合(データベースで確認)、トリガーを作成する必要があります!

21
Martin

私のpostgres 9.6の謙虚な経験では、些細なサイズを超えるテーブルに対しては、カスケード削除は実際には機能しません。

  • さらに悪いことに、削除カスケードが進行している間、関連するテーブルはロックされているため、それらのテーブル(および場合によってはデータベース全体)は使用できません。
  • さらに悪いことに、削除カスケード中に何をしているのかをpostgresに伝えるのは困難です。時間がかかっている場合、どのテーブルが遅くなっていますか?おそらくpg_stats情報のどこかにあるのでしょうか?わかりにくいです。
1
Gordon Vidaver