【发布时间】:2018-04-21 03:16:32
【问题描述】:
让我们以关系数据库为例,例如MySQL。为简单起见,我将专注于重要的事情:拥有一个包含订单的表,其中包含 order_id(主键)order_date 之类的字段和一个外键 fk_supplier,它引用表中的主键 supplier .该表还有一个名为supplier_name 的字段。
现在,让我们想象一下,有一个 php-website 显示了在表格中进行的所有订单。表的每一行都由order_id、order_date 和supplier_name 组成(sql 语句连接了两个表)。
到目前为止一切都很好。现在,有人更改了其中一个订单中引用的一个供应商的名称:历史数据变为不真实或虚假。
我的问题是:防止这种情况的最佳做法是什么?我想到了三个解决方案:
- 不要让用户更改订单中引用的供应商数据行。如果名称发生变化,让他添加新的供应商。
- 始终将当前供应商数据(例如供应商名称)与订单记录一起保存,不要使用主键/外键引用。
- 引入时间片:每次,供应商的一个重要属性(如名称)发生变化,创建一个新的时间片。不仅参考订单中的supplier_id,还参考对应的时间片。
所有这些方法都有优点和缺点。例如,第 2 点似乎很脏,并且违反了关系数据库的所有规则。在我看来,第 3 点通常是要走的路。但是需要很多努力,编程明智。用户体验/可用性也变得非常糟糕。
我想听听经验丰富的开发人员和数据库设计人员如何处理这个问题。
【问题讨论】:
-
我将作为选项 2 实施,但我看不到(从您的描述)为什么您需要以旧订单存储过时的(以前的)供应商名称? IMO 供应商表应该有
SupplierID INT这是主键和名称是无关紧要的。 -
我会考虑选项 3 的变体,您只需创建一个新的供应商并添加一个额外的列来存储
OriginalSupplierID,而不是时间片,以便能够跟踪关系。可能有更好的解决方案,但需要更多背景信息。 -
在这种情况下,我的选择是 2 但您仍然将 PK 和 FK 保留到供应商记录,同时将供应商详细信息的快照保存在另一个表中,例如OrderInvoiceDetails。
-
至于
"Point 2 e.g., seems pretty dirty and against all rules of a relational database":不,不是。您存储完整的订单,以便重新打印。它独立于当前的供应商名称和地址,因此您将数据与订单一起存储。这是一个有效的选项,不违反数据库规范化。 -
@whocares81:我的意思是:这不是多余的。您存储带有名称和地址的订单。同一供应商的另一个订单可以有另一个名称和地址。同时,供应商可以拥有另一个名称和地址。这有什么多余的?这是存储数据的正确方法。顺便说一下,订单中的商品价格也是如此。但是,正如您已经展示的那样,还有其他选择。我要说的是:这不违反规范化并且是一个有效的选择。
标签: mysql sql-server database relational