何时使用“ON UPDATE CASCADE”

时间:2009-09-26 15:41:49

标签: 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
);

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

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

  2. 如果(1)为真,则表示如果parent.id不可更新(或永远不会更新),则不需要使用“ON UPDATE CASCADE”,例如{{1}或者始终设置为AUTO_INCREMENT。是吗?

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

  4. 如果我(出于某种原因)将TIMESTAMP更新为不存在的内容,会自动删除吗?

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

    请说清楚。

7 个答案:

答案 0 :(得分:425)

如果你的主键只是一个自动递增的标识值,那么你就没有真正使用ON UPDATE CASCADE。

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

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

答案 1 :(得分:76)

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

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

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

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

答案 2 :(得分:26)

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

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

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

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

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

马克

答案 3 :(得分:14)

前几天我遇到触发器问题,我发现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
);

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

答案 4 :(得分:4)

我的评论主要是参考第3点:如果我们假设父键不可更新,在什么情况下ON UPDATE CASCADE适用?这是一个案例。

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

答案 5 :(得分:3)

这是一个很好的问题,我昨天也有同样的问题。我想到了这个问题,特别是如果存在类似“ON UPDATE CASCADE”的东西,那么很幸运,SQL的设计者也考虑过这个问题。我同意Ted.strauss,我也评论了Noran的案例。

我什么时候使用它?就像Ted指出的那样,当你一次处理几个数据库,并且其中一个数据库中的修改,在一个表中,在Ted称之为“卫星数据库”时有任何类型的再现,不能与原始数据库保持一致ID,并且出于任何原因,您必须创建一个新ID,以防您无法更新旧数据(例如由于权限,或者如果您在如此短暂的情况下搜索坚牢度不应该完全和完全尊重规范化的总规则,仅仅因为它将是一个非常短暂的效用)

所以,我同意两点:

(A.)是的,很多时候更好的设计可以避免它; BUT

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

答案 6 :(得分:1)

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

删除父表中行的操作

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

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

更新父表中行的操作

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

  • ON UPDATE NO ACTION:SQL Server引发错误,并在父表中的行上回退更新操作。
  • ON UPDATE CASCADE:更新父表中的行后,SQL Server会更新子表中的相应行。
  • ON UPDATE SET NULL:更新父表中的相应行时,SQL Server会将子表中的行设置为NULL。请注意,要执行此操作,外键列必须为空。
  • ON UPDATE SET DEFAULT:SQL Server为子表中具有更新的父表中相应行的行设置默认值。
FOREIGN KEY (foreign_key_columns)
    REFERENCES parent_table(parent_key_columns)
    ON UPDATE <action> 
    ON DELETE <action>;

请参见the reference tutorial