MySQL:触发条款“而不是更新”

时间:2012-05-01 10:43:46

标签: mysql database-design triggers event-triggers

我正在尝试创建一个记录了历史记录的数据库(经验表明,您必须在某一天或另一天内完成此操作)。

我在这里问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 id_produit=@last
    WHERE id_produit = OLD.id;
    UPDATE produit_attribut SET id_produit=@last
    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似乎并不支持这一点。

所以我的问题是两者概念性(=你有任何其他"原则"可能有效)和/或技术(=你可以使这个触发工作)。

2 个答案:

答案 0 :(得分:0)

  

如果我的代码工作正常,我的所有问题都消失了。该死的,它不起作用:

通常,您不能在表A上触发器触发器插入表A中 - 因为这可能导致无限循环。 (Oracle术语中的触发变异)

我个人不会使用触发器来做这件事。触发器可以执行“审计日志记录” - 但这不是您想要的。

我建议你以编程方式解决它 - 使用PHP函数或MySQL存储过程(无论你喜欢什么),你称之为“ModifyProduit”。

然后代码基本上会执行上面的触发器操作。 (将代码设置为当前行的date_v_end可能更容易,然后插入一个完整的新行。这样您就不必更新引用的表了)

答案 1 :(得分:0)

你可以用这样的辅助表做一个表的历史(我已经在mysql上为很多表做了这个并且速度非常好):

  • table produit_history具有与produit + 2个附加列相同的结构:“history_start DATETIME NOT NULL”和“history_stop DATETIME DEFAULT NULL”。
  • produit表上有3个触发器:
    • 插入后:在此触发器中有一个简单的插入produit_history的相同数据,其中history_start = NOW()和history_stop = NULL(NULL表示当前行有效)
    • 更新后:此触发器执行两个查询。第一个是不更新,如下所示:
      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 (history_start <= "interesting_time" AND (history_stop IS NULL OR history_stop > "interesting_time"))