如何跟踪参考表的历史更改?

问题描述:

这是Web应用程序中非常普遍的事情。如果我有一个用户表,并且想跟踪对用户表所做的所有更改,则可以使用数据库插入和更新触发器将这些更改保存在user_history表中。如何跟踪参考表的历史更改?

但是如果我有user_products表,我有user_id,product_id,cost。当我在系统中添加一个用户时,可以说我有两个与该用户相关的产品。所以我的user_products表将为该用户提供两行。

user_id product_id cost 
1  10   1000 
2  20   2000 

现在,如果我去编辑用户页面和删除产品1,增加产品3,成本的变化对产品2从2000年到3000

所以通常我删除所有记录的user_id 1从user_product表,然后为新产品做一个新的插入。

所以它不是一个定期的更新,而是一个删除然后插入。因此我无法跟踪历史变化。

理想我想知道,我已删除的产品1,高附加值产品3,改变成本的产品2从2000年到3000

编辑1: -

我没有做一个更新。我正在做一个删除,然后插入。所以我删除记录与产品id 2和成本2000.然后再次插入记录与prod id 2但成本3000.所以技术上它的删除和插入,但逻辑上只有成本从2000更改为3000.如果我检查时同时执行查询它会说我删除了产品ID 2,然后添加产品与ID 2是相同的。但是,我希望能够看到成本已经从2000年chnaged到3000

+1

为什么不只是做一个更新而不是删除和插入? – 2012-04-10 03:57:51

+0

@丹A.它基本上是从用户到产品的一对多关系。用户可以有100多种产品。如果用户现在有10个产品。他以后可能会有40种产品。如果我向用户添加新产品,我将不得不检查该用户产品映射是否存在于表中。如果是,则更新,如果没有,则插入。所以对我来说,很容易删除一切,然后再插入所有产品。这样我不必检查现有的和新的记录,并相应地运行插入或更新查询。 – ashishjmeshram 2012-04-10 04:05:32

+3

当您尝试追踪历史记录时,您无法检查是否存在要更新的产品会带来任何便利。在我看来,最好通过实际进行“技术更新”来执行“逻辑更新”。如果您决定在产品记录中添加“create_date”和“last_updated”列,该怎么办?如果您更新现有记录,这样做很简单。 – 2012-04-10 14:03:37

一种选择是创建一个由触发器填充上user_product一个user_product_history表,然后定义转换旧“删除”排在历史表为update,如果该行被随后插入的触发器。

CREATE TABLE user_product_history (
    user_id   number, 
    product_id  number, 
    cost   number, 
    operation_type varchar2(1), 
    operation_date date 
); 

CREATE TRIGGER trg_user_product_history 
    AFTER INSERT OR UPDATE OR DELETE ON user_product 
    FOR EACH ROW 
DECLARE 
    l_cnt integer; 
BEGIN 
    IF(deleting) 
    THEN 
    insert into user_product_history(user_id, product_id, cost, operation_type, operation_date) 
     values(:old.user_id, :old.product_id, :old.cost, 'D', sysdate); 
    ELSIF(updating) 
    THEN 
    insert into user_product_history(user_id, product_id, cost, operation_type, operation_date) 
     values(:new.user_id, :new.product_id, :new.cost, 'U', sysdate); 
    ELSIF(inserting) 
    THEN 
    select count(*) 
     into l_cnt 
     from user_product_history 
    where operation_type = 'D' 
     and user_id  = :new.user_id 
     and product_id  = :new.product_id; 
    if(l_cnt > 0) 
    then 
     update user_product_history 
     set operation_type = 'U', 
      operation_date = sysdate, 
      cost   = :new.cost 
     where operation_type = 'D' 
     and user_id  = :new.user_id 
     and product_id  = :new.product_id; 
    else 
     insert into user_product_history(user_id, product_id, cost, operation_type, operation_date) 
     values(:new.user_id, :new.product_id, :new.cost, 'I', sysdate); 
    end if; 
    END IF; 
END; 

从效率的角度来看,然而,这样的删除和插入,而不是更新将意味着,你将远远更多的负载您的数据库比是必要的。你会做比实际需要更多的I/O。最终你会得到更复杂的代码来处理更改。你几乎肯定会更好地弄清楚已经发生了什么变化,然后只是更新这些行。

+0

感谢您的答案。请参阅我已更新我的问题。这个触发器和桌子是否适用于我的情况? – ashishjmeshram 2012-04-10 03:55:11

+0

@Ashish - 我发布了一个示例,说明如何调整触发器以将删除后的插入视为历史记录表中的逻辑更新。但是,如果你只是做一个更新,你会更好。 – 2012-04-10 04:42:23

+2

尝试将历史记录表中的插入转换为更新的另一个缺点是,您无法真正区分实际更新和实际删除,然后在稍后插入。 – 2012-04-10 15:33:43

我不知道是否有一个“标准”的方式或简单的一个,但我的经验,你必须做你自己.. 当然,你不需要为每个表编写一个特定的方法,而只需要一个处理所有更新SQL的通用方法,根据你的表结构,这是一个聪明的东西。 例如: 可以定义将有一个历史表: ID - 表名 - 表记录的ID - 字段列表更新 - 值的列表前更新 - 更新完毕后

值的名单,然后,到你的代码,你应该有一个抽象类,将处理SQL查询:上更新,调用将解析SQL查询和记录插入该表的方法,即使你要查询的SELECT来检索更新前的数据(开销最小,因为SELECT只使用少量资源,并且可以使用数据库服务器缓存)。 最后,当显示相对于记录的信息,比方说用户,您可以添加代码来显示该表和该用户ID的历史。

希望它能帮助你。

+0

谢谢你的回答。但我没有做更新。我正在做一个删除,然后插入。所以我删除记录与产品id 2和成本2000.然后再次插入记录与prod id 2但成本3000.所以技术上它的删除和插入,但逻辑上只有成本从2000更改为3000.如果我检查时同时执行查询它会说我删除了产品ID 2,然后添加产品与ID 2是相同的。但我希望能够看到成本从2000到3000 – ashishjmeshram 2012-04-10 03:48:34

+0

,但我提到的解决方案是相同的:当我写“更新”时,我的意思是“插入/更新/删除”。为了为您完成解决方案,我建议您为操作插入另一列:update/insert/delete。然后进入方法,你可以很容易地填写这个列,因为SQL查询以选择,插入,更新或删除开始......这就是我现在用我的应用程序!它工作正常。当然,我的历史有更多的领域,如user_id,日期,sql被执行... – 2012-04-10 04:09:16