数据更改时保持历史数据库关系完整性

时间:2014-03-04 09:11:29

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

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

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

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
    
  3. 这两种方法都有其优点,解决方案1看起来更简单......你看到解决方案1有问题吗?这个“历史数据”问题通常如何解决?对于我的项目,我必须为这样的2-3个模型解决这个问题,你认为什么是最好的解决方案?

2 个答案:

答案 0 :(得分:0)

以物品价格为例,你也可以:

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

    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月的第一个改为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
    

答案 1 :(得分:0)

我会选择PaperTrail,它保留了我所有模型的历史,甚至是它们的毁灭。如果它不能缩放,我总是可以稍后切换到第2点。