カスケード(ON DELETE / UPDATE)動作の適切な説明


98

私は毎日スキーマを設計していませんが、そうするとき、私は管理を容易にするためにカスケード更新/削除を正しくセットアップしようとします。カスケードがどのように機能するかは理解していますが、どのテーブルがどのテーブルであるかを思い出すことはできません。

例えば、場合、私は2つのテーブルを持っている- ParentChildの外部キーと- Childその参照Parentして持っているON DELETE CASCADEカスケードの引き金と記録しているが、カスケードによって削除されます記録し、?私の最初の推測はChildParentレコードはChildレコードに依存しているため、レコードが削除されるとレコードが削除されることですParentが、これON DELETEはあいまいです。それは、削除を意味することができParentたときに、レコードをChildレコードが削除されたか、削除意味するかもしれないChild時にレコードをParent削除されます。それでどちらですか?

構文がON PARENT DELETE, CASCADEであったON FOREIGN DELETE, CASCADEか、またはあいまいさを排除するために似たものがあればいいのにと思います。これを覚えているニーモニックはありますか?

回答:


138

用語ParentChild用語が気に入っており、覚えやすいと思う場合は、ON DELETE CASCADEto の翻訳が好きかもしれませんLeave No Orphans!

つまり、Parent行が削除(キル)された場合、孤立した行はChildテーブル内で存続しません。親行のすべての子も殺されます(削除されます)。これらの子のいずれかに孫(別の外部キーを介した別のテーブル)があり、ON DELETE CASCADE定義されている場合、これらも削除する必要があります(カスケード効果が定義されている限り、すべての子孫)。

FOREIGN KEY制約自体としても記載することができたAllow No Orphans!(最初の場所で)。いいえChild、それはしていない場合は、これまで、子テーブルに(書かれた)許されるべきではないParent(親テーブルの行)。

一貫性をON DELETE RESTRICT保つために、を(より積極的ではYou Can't Kill Parents!ない)に変換できます。子のない行のみを削除(削除)できます。


3
アナロジーにはまだ何かが欠けていると感じます。子供が複数の親を持つことはできませんか?この場合、1人の親を殺すと子供は孤児になりますか?
Jus12

7
@ Jus12いいえ、外部キー制約は1つの親のみで機能します。これは、この側面に関する良い類推ではありません。
ypercubeᵀᴹ

1
@ypercube:これは許可されていませんか?Order(custID, itemID, orderID)ここでcustIDCustomers表の主キーをitemID参照し、Items表の主キーを参照します。Order両親が2人いませんか?
Jus12 14年

4
@ Jus12もちろんこれは許可されますが、2つの外部キー制約になります。その場合、すべての子(注文)には親(顧客)と親(アイテム)があります。ただし、2つのFKの動作は異なる場合があります。(たとえば、顧客を殺すとすべての(注文)子供が殺されるが、アイテムを殺しても注文は殺されない可能性があります。)
ypercubeᵀᴹ14年

1
「孤児」と言わなくても、親の例えは機能します。子エントリの2つの別々の親への2つの参照がある場合、これは離婚したカップルの子と見なすことができます。制限:「お母さんを殺すことはできません」カスケード:「お父さんを殺すと、私も死にます」
クリストファーマク

31

たとえば、親レコードが子レコードを所有する親と子の2つのテーブルがある場合、どのテーブルがON DELETE CASCADEを必要としますか?

ON DELETE CASCADEは、外部キー宣言のオプションの句です。そのため、外部キーの宣言に伴います。(「子」テーブルでの意味。)

...子レコードが削除されたときに親レコードを削除することを意味する場合もあれば、親が削除されたときに子レコードを削除することを意味する場合もあります。それでどちらですか?

外部キー宣言を解釈する1つの方法は、「この列のすべての有効な値は、「that_table」の「that_column」から取得されます。」「子」テーブルの行を削除するとき、誰も気にしません。データの整合性には影響しません。

「親」テーブルから「that_table」から行を削除すると、「子」テーブルの有効な値から有効な値が削除されます。データの整合性を維持するには、「子」テーブルに対して何かをする必要があります。カスケード削除は、できることの1つです。


2

SQL:2011仕様

には5つのオプションがON DELETEあり、ON UPDATEそれはに適用できますFOREIGN KEY。これらは<referential actions>、SQL:2011仕様から直接呼び出されます

  • ON DELETE CASCADE:参照先テーブルの行が削除されると、参照元テーブル内の一致するすべての行が削除されます。
  • ON DELETE SET NULL:参照されるテーブルの行が削除された場合、参照するテーブルのすべての一致する行のすべての参照する列はnullに設定されます。
  • ON DELETE SET DEFAULT:参照されるテーブルの行が削除された場合、参照するテーブルの一致するすべての行のすべての参照する列は、列のデフォルト値に設定されます。
  • ON DELETE RESTRICT:参照するテーブルに一致する行がある場合、そのテーブルの行を削除することは禁止されています。
  • ON DELETE NO ACTION (デフォルト):参照削除アクションはありません。参照制約は、制約チェックのみを指定します。

外部キーは、依存関係を確立します。<referential action>関係が溶解されたときに何が起こるかを決定します。

例/比Meta /説明

この例では、社会と経済の一般的なモデルを受け入れます。ここで、すべてbusinessは、bourgeoisieを通じてを通じて関係を維持する会社ですfatcat_owner

CREATE TABLE bourgeoisie(
  fatcat_owner varchar(100) PRIMARY KEY
);
INSERT INTO bourgeoisie(fatcat_owner) VALUES
  ( 'Koch Brothers' );

CREATE TABLE business (
  name         varchar(100),
  fatcat_owner varchar(100) REFERENCES bourgeoisie
);
INSERT INTO business(name, fatcat_owner)
  VALUES ('Georgia-Pacific', 'Koch Brothers');

すべてのbusinessESがbourgeoisie彼らによって直接影響を受けているfatcat_owner場合、あなたはfatcat_ownerS をパージし、階級のない社会を持っているとき、あなたは労働者革命後に何をしますか?

-- Viva la revolución 
BEGIN;
  DELETE FROM bourgeoisie;
END;

ここにはいくつかのオプションがありますが、

  • 革命を止めてください。SQLの用語では、RESTRICT。一部の人々は、これがより小さな悪であると信じていますが、彼らは通常間違っています。
  • 続けてください。その場合、革命が起こったときにSQLには4つのオプションがあります。

    • SET NULL-空白のままにします。誰が知っている、多分資本主義が復活bourgeoisieし、オリガルヒがの役割を果たしfatcat_ownersます。重要な注意点として、列はNULLABLE(ではなくNOT NULL)でなければなりません。そうしないと、このようなことが起こり得ません。
    • SET DEFAULT-おそらくあなたはこれDEFAULTを処理したことがありますか?A DEFAULTは関数を呼び出すことができます。スキーマはすでに革命に対応しているかもしれません。
    • CASCADE-ダメージコントロールはありません。が成功した場合bourgeoisie、そうしますbusiness。ビジネスがいる場合必要があります持っているfatcat_pig、そして時にはそれは、データを失うことなく、非ビジネスを持っているために、より理にかなってbusinessテーブル。
    • NO ACTION-これは基本的にチェックを遅らせる方法です。MySQLではに違いはありませんRESTRICTが、PostgreSQLでは次のことができます。

      -- Not a real revolution.
      -- requires constraint be DEFERRABLE INITIALLY DEFERRED
      BEGIN;
        SET CONSTRAINTS ALL DEFERRED;
        DELETE FROM bourgeoisie;
        INSERT INTO bourgeoisie VALUES ( 'Putin' );
        UPDATE business SET fatcat_pig = 'Putin';
      END;
      

      このようなシステムでは、トランザクションがコミットされる前にのみ制約が検証されます。これにより、革命が止まる可能性がありますが、ある程度の「回復」のために、トランザクションで回復することができます。


referenced表には、親テーブルと意味referencingの表は、子テーブルを意味しますか?
sg552

@ sg552はい、正しく理解しました。
informatik01

0

簡単なニーモニックは

親CASCADEのDELETE ON [削除による]ここに

これは、どの削除(親の削除)がカスケードされるか、ON DELETE CASCADEステートメントがどこに行くか(子に対して)、何が削除されるか(子)を示します。


-3

まあ、おそらく構文を合理化できます。Pythonの例を見てみましょう:

class Parent(self):
    # define parent's fields

class Child(self):    
    # define child's fields
    parent_pk_is_childs_foreign_key = models.ForeignKey(Parent, on_delete=models.CASCADE)

この行の内容は、親のon_delete(ステートメントで誤って言及されています)です。削除を子にカスケードしてください。CASCADEステートメントが子レベルで定義されている理由は、削除する必要がある子をマークするためです。

たとえば、別のクラスがあった場合

class GrownUpChild(self):    
        # define grown up child's fields
        parent_pk_is_childs_foreign_key = models.ForeignKey(Parent, on_delete=models.DO_NOTHING)

この構造は、孤立しているにもかかわらず、どの子を削除する必要があるか(Child)およびどの子を残すか(GrownUpChild)を明確に示します。

[編集:議論の文脈、特にon_delete = models.CASCADEなどの場合]では、監査と報告の理由、および偶発的な回復のために、削除された親の子を残すことが望ましい動作であることがよくあります。削除。[もちろん、エンタープライズレベルのソフトウェアは、このような動作を中心に構築され、削除されたレコードを実際に削除するのではなく、deleted = 1としてフラグを立てます。さらに、deleted = 1のレコードをデータベースからパージする機能があります。これは通常、UI管理者によって実行され、多くの場合、データベース管理者側の関与を避けます。


1
「実際には、監査と報告の理由、および誤った削除の回復のために、削除された親の子を残すことが望ましい動作であることがよくあります」 -(健全な)データベースでは悲惨なことです。
dezso

@dezsoご意見ありがとうございます。ただし、複数のエンタープライズレベルのCRMシステムがまさにそれを行います。
ジョージモギ

TBHは、これ以上賢明なことはしません。私はかつてそのようなアプローチの結果としてのたわごとを修正する割り当てを受けました-給料を除いて喜びはありません。
-dezso

あなたは精通したデータベース管理者のように聞こえます:)私はあなたの主張を完全に聞くことができます。私がそれを行う上記のソフトウェアは、実際に削除されたものを手動で削除する機能を持っています= 1この呼び出しを行うのはアプリの管理者次第です。通常、データベース管理者はこの側面の維持にも関与していません。それに、全体のソフトウェアのデータベースクラスは、概念を中心に構築されているので、それは常にCRUD操作で削除フラグをチェック
ジョージMogilevskyを

はい、それは既知の正気のパターンです-しかし、それを反映するために上の表現を変更する必要があるかもしれません。
-dezso
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.