2012-05-01 59 views
2

我試圖創建一個記錄歷史記錄的數據庫(經驗表明,你將不得不做這一天或另一天)。MySQL:觸發條款「而不是更新」

我在這裏問了database-design-how-to-handle-the-archive-problem但沒有比鏈接here更好的了。

我的問題是關於哪裏做的代碼和技術上,如何(MySQL的給我頭痛)。首先我已經開始在Php中做這件事:在做任何插入之前,將記錄標記複製爲「過時」,然後修改記錄。

但是存在一個依賴性問題(許多許多和許多對待關聯也必須更新),這意味着編碼(這種或那種)所有依賴和更新隨表(不可接受)。

所以我正在考慮做數據庫服務器端的所有工作。這將大大簡化我的PHP代碼。

問題是我必須在修改它之前「歸檔」當前記錄。要這樣做,代碼必須在trigger "before update"

這裏是我的代碼:

DELIMITER ;; 

DROP TRIGGER IF EXISTS produit_trigger_update_before; 

CREATE TRIGGER produit_trigger_update_before 
BEFORE UPDATE ON produit 
    FOR EACH ROW BEGIN 
    /* */ 
    INSERT INTO produit SET 
     id_origine  = OLD.id_origine, 
     date_v_creation = OLD.date_v_creation, 
     date_v_start = OLD.date_v_debut, 
     date_v_end  = NOW(), 
     ... 
     last_record  = OLD.last_record; 

    /* Dependancies : */ 
    SET @last=LAST_INSERT_ID(); 
    UPDATE categorie_produit SET [email protected] 
    WHERE id_produit = OLD.id; 
    UPDATE produit_attribut SET [email protected] 
    WHERE id_produit = OLD.id; 
    END;; 

DELIMITER ;; 

如果我得到這個代碼的工作,我所有的問題都沒有了。但是,該死的,它不工作:

mysql> update produit set importance=3; 
ERROR 1442 (HY000): Can't update table 'produit' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. 
mysql> Bye 

在這種page有一個工作示例,它使用INSTEAD OF UPDATE子句中的觸發器。 MySQL似乎不支持這一點。所以我的問題是這兩個概念(=你有任何其他「原則」可以工作)和/或技術(=你能使這個觸發器工作)。

+0

通常的策略是離開行的「base」表,並將舊值複製到歷史記錄表中。這樣你就不需要應付依賴關係。 –

回答

0

如果我得到這個代碼工作,我所有的問題都沒有了。但該死的,它不工作:

作爲一項規則,你不能在表上觸發一個觸發器插入表A - 因爲這可能會導致無限循環。 (觸發器在Oracle中的突變)

我個人不會這樣做使用觸發器。觸發器可以做「審計日誌記錄」 - 但這不是你想要的。

我建議你以編程方式解決它 - 無論是使用PHP函數還是使用MySQL存儲過程(無論您的首選項),您稱之爲「ModifyProduit」。

然後代碼基本上會做上面的觸發器。 (將代碼設置爲當前行的date_v_end可能更容易,然後插入完整的新行。這樣你就不必亂搞了更新你引用的表格)

+1

嗨,爲了您的信息,Oracle可以在同一個表上的一個觸發器ONBEFOREUPDATE中插入一個新行。 PostGRESQL相同。但不是MySQL。結論:使用* real *數據庫系統。你只需要小心,不要做你所解釋的(「觸發突變」)。從現在開始,我將盡我所能只處理PostGRESQL或Oracle **'; ^)'** –

0

你可以用這樣的輔助表格做一個錶的歷史記錄(我在mysql上做了很多表,並且速度非常好):

  • produit_history具有相同的結構produit + 2附加列: 「history_start DATETIME NOT NULL」 和 「history_stop DATETIME DEFAULT NULL」。
  • 有上produit表3個觸發器:
    • INSERT AFTER:在此觸發器有一個簡單的插入件插入帶有history_start同一數據=的produit_history NOW()和history_stop = NULL(NULL意味着當前行是有效的)
    • AFTER UPDATE:此觸發器執行兩個查詢。第一個是這樣的更新:
      UPDATE produit_history set history_stop = NOW() WHERE id_origine = OLD.id_origine AND history_stop IS NULL;
      第二個查詢是一個插入與AFTER INSERT觸發器中的插入相同。
    • AFTER DELETE:此觸發器有一個簡單的更新,它與AFTER UPDATE中的更新相同。

然後,您可以查詢這個歷史表,並在任何時候你有興趣在獲取快照以下where條件:

WHERE (history_start <= "interesting_time" AND (history_stop IS NULL OR history_stop > "interesting_time"))