级联(ON DELETE/UPDATE)行为的良好解释

Joh*_*ron 135 mysql foreign-key

我不是每天都设计模式,但是当我这样做时,我会尝试正确设置级联更新/删除以使管理更容易。我了解级联的工作原理,但我永远记不起哪个表是哪个。

例如,如果我有两个表 -Parent并且Child- 在Child该引用上有一个外键Parent并且 has ON DELETE CASCADE,哪些记录触发级联,哪些记录被级联删除?我的第一个猜测是Child记录被删除时Parent记录被删除,因为Child记录依赖于Parent记录,但这ON DELETE是不明确的;这可能意味着在删除Parent记录时删除记录Child,也可能意味着在删除Child记录时删除记录Parent。那么它是哪个?

我希望语法是ON PARENT DELETE, CASCADEON FOREIGN DELETE, CASCADE或者类似的东西来消除歧义。有没有人有记住这一点的助记符?

ype*_*eᵀᴹ 188

如果您喜欢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!只能杀死(删除)无子行的行。

  • @ Jus12 不,外键约束仅适用于 1 个父级。关于这方面,这不是一个很好的类比。 (9认同)
  • @Jus12 这当然是允许的,但这将是 2 个外键约束。那么每个孩子(订单)都会有一个父母(客户)和一个父母(项目)。不过,这 2 个 FK 的行为可能会有所不同。(因此,例如,可能是杀死客户会杀死他们所有的(订单)子项,但杀死物品不会杀死他们的订单。) (4认同)
  • 我觉得类比中仍然缺少一些东西。一个孩子不能有一个以上的父母吗?在这种情况下,杀死一个父母会使孩子成为孤儿吗? (3认同)
  • 如果我们不说“孤儿”,父类的比喻仍然有效。如果在一个孩子条目中有两个提到两个分开的父母,这仍然可以被视为离婚夫妇的孩子。限制:“我不会让你杀我妈妈” Cascade:“如果你杀了我爸爸,我也会死” (2认同)

Mik*_*ll' 40

例如,如果我有两个表 - Parent 和 Child - 其中 Child 记录归 Parent 记录所有,哪个表需要 ON DELETE CASCADE?

ON DELETE CASCADE 是外键声明中的可选子句。所以它外键声明一致。(意思是,在“子”表中。)

...这可能意味着在删除子记录时删除父记录,或者在删除父记录时删除子记录。那么它是哪个?

解释外键声明的一种方法是,“此列的所有有效值都来自 'that_table' 中的 'that_column'。” 当您删除“子”表中的一行时,没有人关心。它不会影响数据完整性。

当您从“父”表(从“that_table”)中删除一行时,您将从“子”表的可能值中删除一个有效值。为了保持数据完整性,您必须对“子”表做一些事情。级联删除是您可以做的一件事。


章节和诗句,来自PostgreSQL 文档

限制和级联删除是两个最常见的选项。RESTRICT 防止删除引用的行。NO ACTION 意味着如果检查约束时仍然存在任何引用行,则会引发错误;如果您未指定任何内容,则这是默认行为。(这两个选择之间的本质区别是 NO ACTION 允许将检查推迟到事务的后期,而 RESTRICT 不允许。) CASCADE 指定当删除引用的行时,应自动删除引用它的行以及。还有另外两个选项:SET NULL 和 SET DEFAULT。当删除引用的行时,这些会导致引用行中的引用列分别设置为空值或它们的默认值。请注意,这些并不能免除您遵守任何约束条件。例如,如果操作指定了 SET DEFAULT 但默认值不满足外键约束,则操作将失败。


Eva*_*oll 12

SQL:2011 规范

有五个选项ON DELETE,并ON UPDATE可以应用到FOREIGN KEY。这些被调用<referential actions>,直接来自 SQL:2011 规范

  • ON DELETE CASCADE: 如果引用表的一行被删除,则引用表中所有匹配的行都被删除。
  • ON DELETE SET NULL: 如果引用表的一行被删除,则引用表的所有匹配行中的所有引用列都将设置为空。
  • ON DELETE SET DEFAULT: 如果引用表的一行被删除,则引用表的所有匹配行中的所有引用列都将设置为该列的默认值。
  • ON DELETE RESTRICT: 如果该行在引用表中有任何匹配的行,则禁止删除该行。
  • ON DELETE NO ACTION (默认):没有引用删除操作;引用约束仅指定约束检查。

外键建立依赖关系。在<referential action>确定何时关系溶解会发生什么。

例子/隐喻/解释

对于这个例子,我们将接受社会和经济的共同模型:其中每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');
Run Code Online (Sandbox Code Playgroud)

如果所有的businesses 都直接受到bourgeoisie他们的影响,fatcat_owner那么在工人革命之后,当你清洗fatcat_owners 并拥有一个无阶级的社会时,你会做什么?

-- Viva la revolución 
BEGIN;
  DELETE FROM bourgeoisie;
END;
Run Code Online (Sandbox Code Playgroud)

你有几个选择,

  • 停止革命。在 SQL 中,RESTRICT. 有些人认为这是较小的邪恶,但他们通常是错误的。

  • 让它继续。如果是这样,当革命发生时 SQL 给了你四个选项,

    • SET NULL——留空。谁知道呢,也许资本主义恢复bourgeoisie了,寡头们出现了fatcat_owners。重要说明,该列必须是NULLABLE(not NOT NULL) 否则这永远不会发生。

    • SET DEFAULT- 也许你有一个DEFAULT处理这个的?A DEFAULT可以调用一个函数。也许你的模式已经准备好革命了。

    • CASCADE- 没有损坏控制。如果bourgeoisie是这样,那么business. 如果一个业务必须有一个fatcat_owner,那么有时丢失数据比在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_owner = 'Putin';
          END;
      
      Run Code Online (Sandbox Code Playgroud)

      在这样的系统中,仅在事务提交之前验证约束。这可能会导致停止革命,但您可以在交易中恢复——某种程度的“恢复”。


小智 6

一个简单的助记符是

ON DELETE 父 CASCADE [通过删除]此处

它告诉您哪些删除(父级的删除)被级联、ON DELETE CASCADE语句的去向(子级)以及删除的内容(子级)。