12

我有一张表格,用于跟踪特定项目的费用。这些费用会随着时间而改变,所以我有两列(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

4 回答 4

16

这个问题的答案可能不受欢迎,但它是:你不能那样做。

触发器无法更新与该行相同的表的另一行,触发器是从中调用的。

这样做的典型方法是创建一个存储过程,插入/更新目标表,然后更新其他行,所有这些都在一个事务中。

于 2012-06-28T15:19:25.790 回答
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 INTO im.split ...
ON DUPLICATE KEY UPDATE
endDate = ADDDATE(startDate, -1);

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

enddate DATE DEFAULT '2050-12-31'
于 2012-06-28T17:06:17.683 回答
3

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

于 2013-11-19T12:34:23.960 回答
1

来自MySQL 文档

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

您将需要找到其他方法来做您想做的事情。

于 2012-06-28T15:19:33.823 回答