何时使用“ ON UPDATE CASCADE”


420

我经常使用“ ON DELETE CASCADE”,但是我从不使用“ ON UPDATE CASCADE”,因为我不确定在什么情况下它会有用。

为了讨论起见,让我们看一些代码。

CREATE TABLE parent (
    id INT NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (id)
);

CREATE TABLE child (
    id INT NOT NULL AUTO_INCREMENT, parent_id INT,
    INDEX par_ind (parent_id),
    FOREIGN KEY (parent_id)
        REFERENCES parent(id)
        ON DELETE CASCADE
);

对于“ ON DELETE CASCADE”,如果id删除带有的父级,则带有的子级中的记录parent_id = parent.id将被自动删除。这应该没问题。

  1. 这意味着在更新id父级时“ ON UPDATE CASCADE”会做同样的事情吗?

  2. 如果(1)为true,则意味着如果parent.id不可更新(或永远不会被更新)(如当它AUTO_INCREMENT始终为或时),则无需使用“ ON UPDATE CASCADE” TIMESTAMP。那正确吗?

  3. 如果(2)不正确,在其他情况下,我们应该使用“ ON UPDATE CASCADE”吗?

  4. 如果我(出于某种原因)child.parent_id将其更新为不存在的内容,然后会被自动删除怎么办?

好吧,我知道,上面的一些问题可以通过编程测试来理解,但我也想知道其中是否有任何数据库供应商依赖性。

请说明一下。


Answers:


468

的确,如果您的主键只是一个自动递增的标识值,则ON UPDATE CASCADE不会真正使用。

但是,假设您的主键是10位UPC条形码,并且由于扩展,您需要将其更改为13位UPC条形码。在这种情况下,ON UPDATE CASCADE将允许您更改主键值,并且具有该值的外键引用的任何表都会相应地更改。

关于#4,如果您将子ID更改为父表中不存在的某些内容(并且具有参照完整性),则应该得到外键错误。


6
只是不得不使用ON UPDATE CASCADE自己来更新旧表中的主键,该旧表不使用自动递增的键
BlueRaja-Danny Pflughoeft

86
  1. 是的,这意味着,例如,如果您做UPDATE parent SET id = 20 WHERE id = 10所有孩子,parent_id的10也将更新为20

  2. 如果您不更新外键引用的字段,则不需要此设置

  3. 想不到其他用途。

  4. 您不能这样做,因为外键约束会失败。


29

我认为您已经确定了要点!

如果你遵循数据库设计最佳实践和你的主键是从来没有更新的(我认为应该总是这样的情况是这样),那么你永远不会真正需要的ON UPDATE CASCADE条款。

Zed提出了一个很好的观点,即如果您使用自然键(例如数据库表中的常规字段)作为主键,那么在某些情况下您需要更新主键。最近的另一个例子是ISBN(国际标准书号),不久前它从10位数字+字符变为。

如果您选择使用代理键(例如,由系统人工生成)作为主键,则不是这种情况(这是我的首选,除了最罕见的情况)。

因此,最后:如果您的主键永不更改,那么您将永远不需要该ON UPDATE CASCADE子句。


什么是“人工系统生成的”密钥?UUID?
HPWD

1
@HPWD:只是系统生成的“人工”键(该值不是基于您的实际数据,也不是从您的实际数据派生的)-它可以是 GUID,INT或BIGINT-或实际上是任何东西。没关系 重点是:该值与您自己的实际数据完全无关-系统会自动为您生成该值。
marc_s

@ marc-s感谢您抽出宝贵的时间写出来。您的回答很合理。
HPWD

2
在我看来,带有自然键的单列表是枚举的一种很好的选择(至少在MySQL DB中是这样)。例如,考虑一个表colors具有行bluepurpleyellow,和一个表productsproduct_color列,作为FK'ed到colors表中。这像枚举一样限制了选择,但是与自动递增的整数不同,它不需要连接即可获得颜色名称。在这种情况下,on update cascade如果您决定改为purple调用它,则是个好主意violet
okdewit

18

几天前,我遇到了触发器的问题,并且我发现这ON UPDATE CASCADE很有用。看一下这个例子(PostgreSQL):

CREATE TABLE club
(
    key SERIAL PRIMARY KEY,
    name TEXT UNIQUE
);

CREATE TABLE band
(
    key SERIAL PRIMARY KEY,
    name TEXT UNIQUE
);

CREATE TABLE concert
(
    key SERIAL PRIMARY KEY,
    club_name TEXT REFERENCES club(name) ON UPDATE CASCADE,
    band_name TEXT REFERENCES band(name) ON UPDATE CASCADE,
    concert_date DATE
);

在我的问题中,我必须定义一些其他操作(触发器)来更新音乐会的表。这些操作必须修改club_name和band_name。由于参考,我无法执行此操作。我无法修改音乐会,然后再处理俱乐部和乐队的桌子。我也无法做到这一点。ON UPDATE CASCADE是解决问题的关键。


3
好评论。我发现在更新级联上也很有用,无论如何您都必须更改ID。我也同意其他人的观点,即这种变化不应该如此典型。例如,在您引用的情况下,我认为在大量数据中,也许使用文本字段关联外键可能不会导致数据库引擎的最快性能。请注意,如果Concert表中的外部关系使用club.SERIAL和band.SERIAL,则名称的更改不会影响表之间的关系。但是,我发现ON UPDATE CASCADE是解决紧急情况的好工具。问候
David L

4
但是,这是一个有问题的设计,它使人为作弊。如果引用s而不是每个表的主键,那么SERIAL在主键中保留两列clubband作为主键有name什么意义?
sm 2015年

简而言之,如果您要复制其他表中的字段并且需要更新该字段,这将很有用。
卡米尔·汤姆斯克(KamilTomšík),

4

我的评论主要是针对第3点:在什么情况下,如果我们假设父键不可更新,那么在什么情况下可以使用ON UPDATE CASCADE?这是一种情况。

我正在处理一个复制方案,其中多个卫星数据库需要与一个主数据库合并。每个卫星都在相同的表上生成数据,因此将这些表合并到主表将导致违反唯一性约束。我正在尝试使用ON UPDATE CASCADE作为解决方案的一部分,在该解决方案中,我会在每次合并期间重新增加键。ON UPDATE CASCADE应该通过自动化部分过程来简化此过程。


3

这是一个很好的问题,我昨天也有同样的问题。我考虑了这个问题,特别是搜索是否存在“ ON UPDATE CASCADE”之类的问题,幸运的是SQL的设计者也曾考虑过这一问题。我同意Ted.strauss的观点,也评论了Noran的案子。

我什么时候用的?就像Ted指出的那样,当您一次处理多个数据库时,其中一个表在一个表中的修改,在Ted所谓的“卫星数据库”中具有任何形式的复制,不能与原始的保存在一起。 ID,并且出于任何原因,您都必须创建一个新ID,以防无法更新旧ID上的数据(例如,由于权限原因,或者在临时性的情况下要搜索固定性)完全不应该完全尊重规范化的总规则,这仅仅是因为它将是一个非常短暂的实用程序)

因此,我同意两点:

(A.)是的,在很多情况下,更好的设计可以避免这种情况;但

(B.)在迁移,复制数据库或解决紧急情况的情况下,幸运的是,当我去搜索它是否存在时,这是一个很棒的工具。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.