【问题标题】:Is it OK to store redundant data in case records from foreign table are deleted如果外部表中的记录被删除,是否可以存储冗余数据
【发布时间】:2017-08-11 18:54:17
【问题描述】:

假设我有一个名为 products 的数据库表,其中包含一个产品列表,主键为 product_id

然后我有一个名为 purchase_order_products 的数据库表,其中包含分配给采购订单的产品列表,外键为 product_id

现在,如果我在两个表之间强制执行引用完整性,它只需要一个采购订单来引用产品,并且永远不可能从数据库中删除该特定产品(除非该采购订单产品也被删除)。

看来我有几个选择:

1) 强制执行参照完整性,并且不允许删除产品。

2) 不要强制参照完整性,如果有人查看过产品不再存在的采购订单,只需将产品名称显示为“未知”或“已删除”。

3) 最后的选择是不仅将产品名称存储在products 表中,而且将其与外键一起存储在purchase_order_products 表中。显然这是多余的数据,但它允许从products 表中删除产品,同时仍然允许用户查看过去作为采购订单一部分的现在不存在的产品的名称。

我倾向于选项 #3,但想知道处理此问题的“正确”方式是什么。

【问题讨论】:

  • 删除是硬删除还是软删除?
  • 还有许多其他选项,甚至还有更多组合。在您定义要求之前,这会使您的问题“过于宽泛”。

标签: mysql database database-design relational-database


【解决方案1】:

您可以强制引用完整性并使用ON DELETE SET NULL,然后在采购订单的product_id 为空时显示“未知”或“已删除”。因此,选项 1 和 2 并不相互排斥。

选项 3 有效。如果它们用于表达不同谓词的关系,那么拥有两个 product_name 副本并不是多余的。 Product <x>'s current name is <y>When purchase_order <z> was created, product <x>'s name was <y> 不同。分别记录当前价格和历史价格是一种常用技术,对于产品的名称或任何其他属性也可以这样做。

【讨论】:

  • 谢谢,我同意为历史目的记录价格和产品名称。如果将来由于某种原因要更改产品名称,您可能希望这反映在以前的订单中
【解决方案2】:

没有理由重复数据。一个简单的解决方案是对产品实施软删除。对于当前产品,最好的方法是设置一个名为 Deleted 之类的适当日期字段,并将其设置为远在未来的日期,例如 9999 年 12 月 31 日。要删除产品,只需将 Deleted 值设置为产品被删除的日期。这样,为了列出当前可用的产品,过滤掉 Deleted 过去的产品。

显示采购订单时,请忽略 Deleted 值,以便显示所有产品,包括不再可用的产品。或者,如果产品不再可用,您可以通过一些指示器显示。

您可能还希望创建一个忽略已删除产品的视图,因为这些时间不适合显示已删除的产品,例如在创建新采购订单时。

您还希望在 products 表上编写一个删除触发器,以将删除过程转换为仅更改 Deleted 字段中的值。您还希望在 API 中有一个函数,以允许在某个日期“删除”产品。也许产品在一个月前被删除,但数据库没有更新。或者该产品将在未来某个日期被移除,因此请继续设置日期。到达该日期后,该产品将从当前产品视图中消失。

【讨论】:

  • “编写删除触发器 [..] 更改 Deleted 字段中的值” - 我很好奇.. 这可能吗?
  • 是的,但我应该指定它必须是“而不是”触发器。这意味着表必须以视图为前面,因为只有视图接受这些类型的触发器。 (SQL Server 除外。)但我通常在大多数表前面至少有一个视图,以便在应用程序和数据之间提供一堵抽象墙。
猜你喜欢
  • 2016-10-16
  • 2021-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-18
  • 1970-01-01
  • 2012-09-01
相关资源
最近更新 更多