2016-07-25 69 views
2

我知道这是一个奇怪的问题,因为我总是被教导使用外键约束。但是,我遇到过一种情况,即在删除引用时必须保留外键引用值用于历史目的。外键总是需要约束吗?

这是一个任务管理系统,任务发生引用包含重复规则的父任务。这个父任务可以被删除,但事件本身必须保持与不存在的父母标识一致。如果找不到父任务,则系统仅返回一个错误 - 例如“父任务不再存在”。父级id不能在级联中设置为null的原因是因为它在事件的其他地方用作识别密钥。

另一个示例:关于从播放列表中删除的YouTube视频怎么样。类似的情况对吗?它在播放列表中被引用,但视频不存在,因此它会在播放列表中返回错误。

难道我根本就没有定义外键,只是简单地将parent_id引用列创建为普通列?我只想确定当遇到一个表引用另一个表的情况时通常如何处理,但前者不受后者存在的约束。

+0

从技术上讲,ON DELETE SET NULL原因将为您处理。如果你的问题是理论上的话,那么:是的,你可以:) – Koshinae

回答

4

有一个约束只是一个强制为数据库定义的语义的技术帮助,即“该列包含的数字不仅是一个INTEGER(32),而且是某个其他表中的记录的标识符”。所以,他们不是绝对必要的,但它:

  • 使得野清晰(自文档)的意图
  • 使您的数据“干净”通过防止被插入
  • 给出了不正确的数据数据库引擎提供有关表的内容的提示,可以使db更高效地执行。

也就是说,完成你所描述的“正确”方式并不是在物理上首先删除父记录。相反,将父项标记为已删除。既然你为了历史目的而保留记录,当然你会希望能够知道父母曾经是什么,即使它不再活跃或有效。

第二种选择是创建一个虚拟的“父记录删除”引用。无论何时删除父项,都会更新剩余的引用来指向虚拟记录。至少你不会依赖错误来实现预期的和有效的行为。

最后,我没有理由不应该能够将外键设置为NULL。这听起来像你正在使用外键作为有问题记录主键的一部分(“正被用作..识别键”)。如果这是问题的根本原因,那么你几乎肯定不应该这样做,首先要改变它。

+0

我想过软删除,但父任务可以由另一个用户创建。其他用户可以订阅这个父任务,因此会出现任务。但是,如果创建原始任务的原始用户希望删除该任务,则预期的结果是将其从数据库中删除,并将事件保存为已订阅的其他用户的记录。我的意思是,当记录的所有者明确要求记录时,不删除记录是否可以(甚至合法)? – chaser

+0

我无法将外键设置为NULL,因为它将原始任务分组为5个子任务的分区变得复杂。这些分组需要在所有情况下保持完好 - 所以这就是为什么需要识别密钥。 – chaser

+0

由于分组问题,不确定第二个选项 - 它基本上与NULL选项类似。但我想,如果我把所有其他设置为NULL,除了ID ...它可以工作吗?至少它就像是一个软删除,没有实际的内容 - 那么它会满足业主对删除的期望......一张满了NULL的表听起来不对,但我不得不多想这些。 .. – chaser

0

难道我根本就没有定义一个外键,只是简单地创建一个普通列的 parent_id引用列?

是的。至少这是我知道的方式,以及我们在工作中如何处理这些东西。

然后,您可能需要在参考列上设置索引。