【问题标题】:Keep historical database relations integrity when data changes在数据更改时保持历史数据库关系的完整性
【发布时间】:2014-04-05 17:15:12
【问题描述】:

当涉及到具有“历史性”的关系时,我会在各种选择之间犹豫不决
价值。

例如,假设用户在某个日期购买了一件物品......如果我只是以经典方式存储它:

transation_id: 1
user_id: 2
item_id: 3
created_at: 01/02/2010

那么很明显,用户可能会更改其名称,商品可能会更改其价格,并且 3 年后,当我尝试创建发生事件的报告时,我得到了虚假数据。

我有两种选择:

  1. 像我之前展示的那样保持愚蠢,但使用 https://github.com/airblade/paper_trail 之类的东西并执行以下操作:

    t = Transaction.find(1);
    u = t.user.version_at(t.created_at)
    
  2. 创建一个类似transaction_userstransaction_items 的数据库,并在进行事务时将用户/项目复制到这些表中。然后结构将变为:

    transation_id: 1
    transaction_user_id: 2
    transaction_item_id: 3
    created_at: 01/02/2010
    

这两种方法都有其优点,但解决方案 1 看起来要简单得多……您发现解决方案 1 有问题吗?这个“历史数据”问题通常是如何解决的?对于我的项目,我必须为 2-3 个这样的模型解决这个问题,你认为最好的解决方案是什么?

【问题讨论】:

  • 你买得起 DB2 吗? :)
  • @NeilMcGuigan:呵呵,不。我想我会选择 PaperTrail,它保留了我所有模型的历史,甚至它们的破坏。如果它不能扩展,我总是可以稍后切换到第 2 点。

标签: ruby-on-rails design-patterns database-design relational-database paper-trail-gem


【解决方案1】:

以商品价格为例,您还可以:

  1. 在交易表中存储当时的价格副本
  2. 为商品价格创建临时表

在交易表中存储价格副本:

TABLE Transaction(
 user_id      -- User buying the item
,trans_date   -- Date of transaction
,item_no      -- The item
,item_price   -- A copy of Price from the Item table as-of trans_date
)

获取交易时的价格很简单:

select item_price
  from transaction;

为商品价格创建临时表:

TABLE item (
   item_no
  ,etcetera -- All other information about the item, such as name, color
  ,PRIMARY KEY(item_no)
)

TABLE item_price(
   item_no
  ,from_date
  ,price
  ,PRIMARY KEY(item_no, from_date)
  ,FOREIGN KEY(item_no)
      REFERENCES item(item_no)
)

第二个表中的数据类似于:

ITEM_NO  FROM_DATE   PRICE
=======  ==========  =====
   A     2010-01-01  100
   A     2011-01-01  90
   A     2012-01-01  50
   B     2013-03-01  60

说从 2010 年 1 月 1 日开始,文章 A 的价格是 100。它从 2011 年 1 月 1 日的第一个变为 90,然后从 2012 年 1 月 1 日再次变为 50。

您很可能会在表中添加一个 TO_DATE,即使它是非规范化(TO_DATE 是下一个 FROM_DATE)。

查找交易时的价格大致如下:

select t.item_no
      ,t.trans_date
      ,p.item_price
  from transaction t
  join item_price  p on(
       t.item_no = p.item_no
   and t.trans_date between p.from_date and p.to_date
  );


ITEM_NO TRANS_DATE PRICE
======= ========== =====
   A    2010-12-31  100
   A    2011-01-01   90
   A    2011-05-01   90
   A    2012-01-01   50
   A    2012-05-01   50

【讨论】:

  • 感谢您的回答,但这是我在第 2 点中提到的专业化......如果我必须经常这样做,您提出的解决方案实际上可以很好地扩展 less .
【解决方案2】:

我将使用 PaperTrail,它保留了我所有模型的历史,甚至它们的破坏。如果它不能扩展,我可以稍后切换到第 2 点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-13
    • 2018-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多