我在MySQL数据库中有两个表-parentchild。我试图基于父表将外键引用添加到我的子表中。 ON UPDATE CASCADEON DELETE CASCADE之间有什么明显区别

我的父表

CREATE TABLE parent (
    id INT NOT NULL,
    PRIMARY KEY (id)
) ENGINE=INNODB;


我的问题是:以下sql查询之间有什么区别。



ON DELETE CASCADE

CREATE TABLE child (
    id INT, 
    parent_id INT,
    INDEX par_ind (parent_id),
    FOREIGN KEY (parent_id) 
        REFERENCES parent(id)
        ON DELETE CASCADE
) ENGINE=INNODB;



ON UPDATE CASCADE

CREATE TABLE child (
    id INT, 
    parent_id INT,
    INDEX par_ind (parent_id),
    FOREIGN KEY (parent_id) 
        REFERENCES parent(id)
        ON UPDATE CASCADE
) ENGINE=INNODB;



ON UPDATE CASCADE ON DELETE CASCADE

CREATE TABLE child (
        id INT, 
        parent_id INT,
        INDEX par_ind (parent_id),
        FOREIGN KEY (parent_id) 
            REFERENCES parent(id)
            ON UPDATE CASCADE ON DELETE CASCADE
    ) ENGINE=INNODB;



查询中是否有错误?这些查询(1、2和3)是什么意思?他们是一样的吗?

评论

ps。为了完整起见,,您在上面谈论的是DDL(数据定义语言)语句,而不是查询。查询通常被认为是DML(数据操作语言SELECT,INSERT,UPDATE,DELETE)

另一个ps再次为了完整性,我想知道默认值是什么。所以我创建了一个没有更新或删除的孩子。然后发生的事情是,您既不能更新也不能删除具有依赖子项的父项。完全有道理,但是MySQL并不总是具有特定特征的模型:-)

#1 楼

关于这个主题的一个很好的话题可以在这里和这里找到。当然,有关MySQL的权威指南也可以在这里找到文档。

在SQL 2003标准中,有5种不同的引用动作:


CASCADE
限制
不采取行动
设置为空
设置默认值

要回答这个问题:



CASCADE


ON DELETE CASCADE表示,如果删除了父记录,则所有子记录也会被删除。我认为这不是一个好主意。您应该跟踪数据库中曾经存在的所有数据,尽管可以使用TRIGGER来完成。 (但是,请参阅下面的注释中的警告)。
ON UPDATE CASCADE表示,如果更改了父主键,则子值也将更改以反映这一点。在我看来,这并不是一个好主意。如果您要定期更改PRIMARY KEY s(甚至完全更改!),则说明您的设计存在问题。再次,请参见注释。
ON UPDATE CASCADE ON DELETE CASCADE意味着如果您是父级,则更改将级联到子级。这相当于前两个语句的结果。


RESTRICT



UPDATE表示任何删除和/或更新父项的尝试都将引发错误。这是未明确指定引用动作的情况下的默认行为。


对于未指定的DELETEAND,默认动作始终为RESTRICT`。





不采取行动




RESTRICT:根据手册。标准SQL中的关键字。在MySQL中,等效于ON DELETE。如果引用表中有相关​​的外键值,则MySQL服务器会拒绝父表的删除或更新操作。某些数据库系统具有延迟检查,而ON UPDATE是延迟检查。在MySQL中,外键约束会立即检查,因此NO ACTIONRESTRICT相同。 /> NO ACTION-再次在手册中。从父表中删除或更新该行,并将子表中的一个或多个外键列设置为NO ACTION。恕我直言,这不是最好的主意,主要是因为没有“时间旅行”的方法-即回溯子表并将与RESTRICT的记录与相关父记录相关联-SET NULL或使用NULL来填充日志记录表以跟踪更改(但请参阅注释)。



设置默认值




NULL。 MySQL尚未执行的SQL标准的另一个(可能非常有用)部分!允许开发人员指定一个值,以将UPDATE或DELETE上的外键列设置为该值。 InnoDB和NDB将使用CASCADE子句拒绝表定义。



如上所述,您应该花一些时间在此处查看文档。

评论


我喜欢您的完整答案,但是我不同意这一说法。 “您应该跟踪数据库中曾经存在的所有数据”-这实际上取决于数据库的设计和目的。例如,食谱定义(我不是在谈论食物-更像是系统配置),当食谱定义被删除时,保留该食谱的关联子代是没有意义的-只是无缘无故地肿了数据库。也是机器系统的工作表-我不再需要数据了;处理并摆脱它。除此之外,您的答案很棒。

– StixO
16年8月15日在13:48

与@StixO相似,我主要喜欢这个答案,但是我不同意更改主键。在某些设计中,这绝对不是一个好主意,但是当您进入分布式数据库时,非常希望主键可以自由地重新分配而不丢失记录的身份。

–加勒特·克拉伯恩(Garet Claborn)
17年8月11日在22:50

“我认为这不是一个好主意。您应该跟踪数据库中曾经存在的所有数据。” -不确定我明白你的意思。如果您要级联“删除”,那么您已经决定需要删除某些内容。如果您决定从不删除任何内容,那么什么都不会层叠。拥有它的好处是,在您的应用程序中,您可以确定当您查找带有外部ID的记录时,便知道该记录将存在,并且如果您决定删除数据库,则不会有任何孤立的行使数据库ating肿。的东西。

–杰夫·瑞安(Jeff Ryan)
18/12/10在0:42

这里的逻辑在某些地方是非常错误的,在我们新的GDPR世界中更是如此。我确实同意这样的观点,即如果主键正在更改,则可能表明出现了某些错误。

–Chuck Le Butt
19-2-19在11:44



如果您以任何规律性(甚至根本没有改变!)更改PRIMARY KEY,则您的设计有问题。您是说ON UPDATE CASCADE更改键的值或键的名称吗?

– Billal Begueradj
19 Mar 4 '19 at 11:09

#2 楼

这两个操作分别是在父表上的引用记录更改其ID以及将其删除时要执行的。

如果执行:

UPDATE parent SET id = -1 WHERE id = 1;


child上至少存在一条记录,其中parent_id = 1,1)将失败;在情况2)和3)中,所有具有parent_id = 1的记录都将更新为parent_id = -1。

如果执行:

DELETE FROM parent WHERE id = 1;


child上至少存在一条记录,其中parent_id = 1,2)将失败;在情况1)和3)中,所有带有parent_id = 1的记录都将被删除。

3)在语法上是正确的。

完整的文档可以在手册上找到。

评论


通过定义1,2,3,而不是依赖从未编辑过的问题,可以更好地解决问题。

– iheanyi
20 Mar 4 '20 at 0:27

#3 楼

我没有足够的声誉来评论以前的答案。因此,我想详细说明一下。

1)ON DELETE CASCADE表示如果删除了父记录,那么所有引用的子记录也会被删除。

2)ON DELETE操作默认为RESTRICT,这意味着父记录上的DELETE将失败。 ON UPDATE CASCADE将在更新父记录时更新所有引用的子记录。

3)请参阅上面1)和2)中的CASCADE操作。

使用父记录时ID作为外键(在子表中)-经验表明a)如果ID是自动生成的序列号,则不要将其用作外键。请改用其他一些唯一的父键。 b)如果ID是GUID,则可以将它们用作外键。当您导出和导入记录或将记录复制到另一个数据库时,您将在此建议中看到智慧。当将自动生成的序列号作为外键引用时,要处理它们会很麻烦。