2012-04-10 93 views
3

這是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

回答

4

一種選擇是創建一個由觸發器填充上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

1

我不知道是否有一個「標準」的方式或簡單的一個,但我的經驗,你必須做你自己.. 當然,你不需要爲每個表編寫一個特定的方法,而只需要一個處理所有更新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