何时使用"ON UPDATE CASCADE"

Naw*_*Man 407 sql foreign-keys foreign-key-relationship

我经常使用"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
);
Run Code Online (Sandbox Code Playgroud)

对于"ON DELETE CASCADE",如果id删除了具有a的父级,parent_id = parent.id则将自动删除子级中的记录.这应该没问题.

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

  2. 如果(1)为真,则意味着如果parent.id不可更新(或永远不会更新),则不需要使用"ON UPDATE CASCADE",就像它是AUTO_INCREMENT或者总是设置为TIMESTAMP.是对的吗?

  3. 如果(2)不成立,在其他什么情况下我们应该使用"ON UPDATE CASCADE"?

  4. 如果我(由于某种原因)更新了child.parent_id不存在的内容,它会被自动删除吗?

好吧,我知道,上面的一些问题可以通过程序测试来理解,但我也想知道这是否依赖于数据库供应商.

请说清楚.

C-P*_*uru 455

确实,如果您的主键只是一个自动递增的标识值,那么您将无法真正使用ON UPDATE CASCADE.

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

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

  • 只需要自己使用`ON UPDATE CASCADE`来更新旧表中的主键,而不使用自动递增的键 (6认同)
  • 当您从数据库中软删除用户时(例如,取消注册该用户,但保留其匿名数据以用于历史统计),您可能还希望对其 ID 进行匿名化(例如,重新生成一个),以便最大限度地减少再次查找其个人资料的方式(其ID 可以在某处的旧日志、以前的电子邮件中找到...) (3认同)

Zed*_*Zed 83

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

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

  3. 想不出任何其他用途.

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


mar*_*c_s 27

我认为你几乎已经指出了这一点!

如果您遵循数据库设计最佳实践,并且您的主键永远不可更新(我认为应该始终如此),那么您从未真正需要该ON UPDATE CASCADE子句.

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

如果您选择使用代理(例如人工系统生成的)密钥作为主键(除了最罕见的情况之外,这将是我的首选),情况并非如此.

所以最后:如果您的主键永远不会改变,那么您永远不需要该ON UPDATE CASCADE子句.

  • 在我看来,带有自然键的单列表是枚举的一种很好且干净的替代方案(至少在 MySQL 数据库风格中)。例如,考虑一个带有“blue”、“purple”、“yellow”行的“colors”表,以及带有“product_color”列的“products”表,被 FK 转换到“colors”表。这限制了像枚举一样的选择,但与自动递增的整数不同,它不需要连接来获取颜色名称。在这种情况下,如果您决定将“紫色”改为“紫罗兰色”,则“更新级联”是个好主意。 (4认同)

Ari*_*jas 17

几天前我遇到触发器的问题,我发现它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
);
Run Code Online (Sandbox Code Playgroud)

在我的问题中,我必须定义一些额外的操作(触发器)来更新Concert的表.这些操作必须修改club_name和band_name.由于参考,我无法做到这一点.我无法修改音乐会,然后处理俱乐部和乐队表.我也不能这样做.ON UPDATE CASCADE是解决问题的关键.

  • 然而,这是一个有问题的设计,这是一个相当人为的例子.如果你引用`name`s而不是每个表的主键,那么将`club`和`band`中的两个`SERIAL`列保留为主键是什么意思? (4认同)
  • 好评.我发现更新级联也很有用,无论如何你必须更改你的ID.我也同意其他人认为这种改变不应该那么典型.例如,在您引用的情况下,我认为在大量数据中,可能使用文本字段关联外键可能不会导致数据库引擎的最快性能.请注意,如果Concert表中的外来关系使用club.SERIAL和band.SERIAL,则名称的更改不会影响表之间的关系.但是,我发现ON UPDATE CASCADE是一个解决紧急情况的好工具.问候 (3认同)

Gui*_*cha 10

和指定当更新和删除父表中的行时将执行哪个操作ON UPDATEON DELETE以下是允许的操作:NO ACTIONCASCADESET NULLSET DEFAULT

\n

删除父表行的操作

\n

如果删除父表中的一行或多行,您可以设置以下操作之一:

\n
    \n
  • ON DELETE NO ACTION:SQL Server 引发错误并回滚对父表中的行的删除操作。
  • \n
  • ON DELETE CASCADE:SQL Server 删除子表中与父表中删除的行相对应的行。
  • \n
  • ON DELETE SET NULL:如果父表中的相应行被删除,SQL Server 会将子表中的行设置为 NULL。要执行此操作,外键列必须可为空。
  • \n
  • ON DELETE SET DEFAULT:如果父表中的相应行被删除,SQL Server 会将子表中的行设置为其默认值。要执行此操作,外键列必须具有默认定义。请注意,如果未指定默认值,可为空列的默认值为 NULL。\n默认情况下,如果您未\xe2\x80\x99 显式指定任何操作,则 SQL Server 将应用 ON DELETE NO ACTION。
  • \n
\n

父表中行的更新操作

\n

如果更新父表中的一行或多行,您可以设置以下操作之一:

\n
    \n
  • ON UPDATE NO ACTION:SQL Server 引发错误并回滚对父表中的行的更新操作。
  • \n
  • ON UPDATE CASCADE:当父表中的行更新时,SQL Server 也会更新子表中的相应行。
  • \n
  • ON UPDATE SET NULL:当父表中的相应行更新时,SQL Server 将子表中的行设置为 NULL。请注意,外键列必须可为空才能执行此操作。
  • \n
  • ON UPDATE SET DEFAULT:SQL Server 为子表中已更新父表中相应行的行设置默认值。
  • \n
\n
FOREIGN KEY (foreign_key_columns)\n    REFERENCES parent_table(parent_key_columns)\n    ON UPDATE <action> \n    ON DELETE <action>;\n
Run Code Online (Sandbox Code Playgroud)\n

请参阅参考教程

\n


Dav*_*d L 6

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

我什么时候用过它?就像 Ted 指出的那样,当您同时处理多个数据库时,其中一个表中的修改在 Ted 所谓的“卫星数据库”中具有任何形式的复制,无法与原始数据库保持一致ID,并且出于任何原因,您都必须创建一个新 ID,以防万一您无法更新旧 ID 上的数据(例如由于权限的原因,或者如果您在一种短暂的情况下寻找快速性,不值得绝对和完全尊重标准化的总体规则,仅仅因为这将是一个非常短暂的效用)

所以,我同意两点:

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

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