parent
,child
。我试图基于父表将外键引用添加到我的子表中。 ON UPDATE CASCADE
和ON 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)是什么意思?他们是一样的吗?
#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
表示任何删除和/或更新父项的尝试都将引发错误。这是未明确指定引用动作的情况下的默认行为。对于未指定的
DELETE
或AND
,默认动作始终为RESTRICT`。 不采取行动
RESTRICT
:根据手册。标准SQL中的关键字。在MySQL中,等效于ON DELETE
。如果引用表中有相关的外键值,则MySQL服务器会拒绝父表的删除或更新操作。某些数据库系统具有延迟检查,而ON UPDATE
是延迟检查。在MySQL中,外键约束会立即检查,因此NO ACTION
与RESTRICT
相同。 /> 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,则可以将它们用作外键。当您导出和导入记录或将记录复制到另一个数据库时,您将在此建议中看到智慧。当将自动生成的序列号作为外键引用时,要处理它们会很麻烦。
评论
ps。为了完整起见,另一个ps再次为了完整性,我想知道默认值是什么。所以我创建了一个没有更新或删除的孩子。然后发生的事情是,您既不能更新也不能删除具有依赖子项的父项。完全有道理,但是MySQL并不总是具有特定特征的模型:-)