MySQL触发NEW行的设置值,并在同一个表中更新另一行

时间:2012-06-28 15:09:50

标签: mysql database-trigger

我有一张表,可以跟踪特定商品的费用。这些费用可能会随着时间的推移而变化,所以我有两列(startDate,endDate),当前的费用总是在不久的将来有一个endDate。我已经有一个触发器用于对输入的新行进行一些计算,但我想要发生的是如果我输入一个已经有条目的项目我想将前一个条目的endDate设置为前一天新条目的startDate和新的endDate到预定的远期日期。以下是我首先尝试的代码:

CREATE
DEFINER=`root`@`%`
TRIGGER `im`.`splitBeforeIns`
BEFORE INSERT ON `im`.`split`
FOR EACH ROW
BEGIN
    SET NEW.tcPercent = (NEW.tcOfficeFee / NEW.globalFee) * 100 , NEW.proPercent = 100 - NEW.tcPercent, NEW.endDate = 20501231;
    UPDATE im.split set endDate = ADDDATE(NEW.startDate, -1) where procKey = NEW.procKey AND endDate = 20501231;
END$$

我得到的错误是:

ERROR 1442: Can't update table 'split' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.

4 个答案:

答案 0 :(得分:12)

对此的回答可能不受欢迎,但它是:你做不到。

触发器不能更新同一个表的另一行作为行,从中调用触发器。

执行此操作的典型方法是创建存储过程,该存储过程插入/更新目标表,然后更新事务中的所有其他行。

答案 1 :(得分:8)

如果在(procKey,EndDate)上定义了UNIQUE KEY,那么也许你可以删除触发器的第二行。同时从触发器中删除硬编码日期。

CREATE
DEFINER=`root`@`%`
TRIGGER `im`.`splitBeforeIns`
BEFORE INSERT ON `im`.`split`
FOR EACH ROW
BEGIN
    SET NEW.tcPercent = (NEW.tcOfficeFee / NEW.globalFee) * 100 , NEW.proPercent = 100 - NEW.tcPercent;
END$$

并像这样做INSERT ON DUPLICATE KEY UPDATE

INSERT INTO im.split ...
ON DUPLICATE KEY UPDATE
endDate = ADDDATE(startDate, -1);

您可能还想在im.split中定义endDate,如下所示

enddate DATE DEFAULT '2050-12-31'

答案 2 :(得分:2)

我设法让它工作,创建一个“包装表”,使用与目标表相同的字段定义,但使用FEDERATED存储引擎。我定义的联合服务器定位到相同的mysql服务器/本身,所以在“localhost”。然后我在触发器表中更改了一行触发器。当然,你必须非常确定你在触发器中做了什么,以避免递归循环。也可能表现不是那么好;我没有测试性能,但它已在生产环境中工作多年。

答案 3 :(得分:1)

来自MySQL Docs

  

在存储的函数或触发器中,不允许修改a   已经被使用(用于读或写)的表   调用函数或触发器的语句。

您需要找到其他方法来做您正在尝试做的事情。