MySQL中出现了“在INSERT触发器中没有OLD行”的错误。

13

我有以下的 MySQL 触发器

SET @iUserId = OLD.LastChangedBy; 

IF NOT NEW.LastChangedBy <=> OLD.LastChangedBy THEN
    SET @iUserId = NEW.LastChangedBy;
END IF;

IF NOT NEW.BookingId<=> OLD.BookingId THEN
    INSERT INTO AuditTrail VALUES (UUID(),@iUserId,'UPDATE','Booking', OLD.BookingId,'BookingType ',OLD.BookingType ,NEW.BookingType ,NOW());
END IF;

这被称为CREATE TRIGGER Booking_AUPD在Booking表上的AFTER UPDATE触发器,每行都会执行。

我遇到的问题是如何在AFTER UPDATE触发器中获取OLD字段的值?


不清楚你的问题是什么。在“更新后触发器”中引用列的值,就像你的示例代码中对 OLD.LastChangedByOLD.BookingID 等的引用一样,可以引用 OLD.col_name 来引用它们更新前的值。 - spencer7593
是的,就是这样。我更新了BookingType字段,现在我需要在AFTER UPDATE触发器中获取BookingType的旧值。这可能吗? - neildt
是的,在觸發器中對 OLD.BookingType 的引用會返回在執行更新語句之前該行的 BookingType 列的值。該引用位於 INSERT 語句的 values 子句中。(我仍然可能不理解您的問題。我們注意到只有在 BookingId 列的 NEW 和 OLD 值不同的情況下才會執行 INSERT。) - spencer7593
是的,这就是我尝试过的,但在应用触发器时,会出现“在插入触发器中没有旧行”错误。 - neildt
1
如果您提供实际返回的错误消息并在问题中提供该消息,这将有助于消除歧义并帮助您获得答案。 - spencer7593
6个回答

25
UPDATE TRIGGER 中,您可以使用 OLD 关键字访问被更新替换的行数据。如果成功,NEW 关键字允许访问即将替换旧行的传入行数据。
一个 UPDATE 触发器的示例是:
CREATE TRIGGER upd_check AFTER UPDATE ON SomeTable
    FOR EACH ROW
    BEGIN
       IF (OLD.LastChangedBy <> NEW.LastChangedBy) THEN
         INSERT INTO AuditSomeTable(ID, LastChangedBy) 
         VALUES (OLD.ID, OLD.LastChangedBy);
       END IF;
    END;

SQLFiddle 这里

根据所创建触发器的类型,OLDNEW 行可能对您不可用:

INSERT TRIGGER

  • 只能访问 NEW 伪行。

UPDATE TRIGGER

  • 可访问 NEWOLD 伪行

DELETE TRIGGER

  • 只能访问 OLD 伪行

即在 INSERT 触发器上没有 OLD 行,在 DELETE 触发器上没有 NEW 行。

OP提出的问题

OP没有提供实际代码,并且评论中提到的错误信息:

There is no OLD row in on INSERT trigger

表明 OP 无意中创建了一个 INSERT TRIGGER,而不是问题中指示的 UPDATE TRIGGER。因为 INSERT 触发器没有 OLD 伪表。


21
最有可能的原因是出现错误。
"There is no OLD row in on INSERT trigger"

你正在执行一个创建 AFTER INSERT 触发器的语句,而不是创建 AFTER UPDATE 触发器。

不能引用行之前的OLD值的原因是,在INSERT之前该行不存在。


9
在触发器主体中,OLD和NEW关键字使您能够访问受触发器影响的行中的列。OLD和NEW是MySQL扩展的触发器功能,它们不区分大小写。
在INSERT触发器中,只能使用NEW.col_name;没有旧行。在DELETE触发器中,只能使用OLD.col_name;没有新行。在UPDATE触发器中,可以使用OLD.col_name来引用更新之前的行的列,使用NEW.col_name来引用更新后的行的列。

3

如果我理解你的问题正确...

答案是否定的!在AFTER INSERT触发器中,你不能使用OLD.col_name。

在mysql参考手册中明确规定:

在INSERT触发器中,只能使用NEW.col_name;没有旧行。在DELETE触发器中,只能使用OLD.col_name;没有新行。在UPDATE触发器中,可以使用OLD.col_name引用更新前的行列和NEW.col_name引用更新后的行列。

触发器语法


0
这是我的完整代码,展示了当某些列的值被更新时触发器将如何工作。
DELIMITER $$

CREATE TRIGGER `salestatus_after_update` AFTER UPDATE ON `salesdata`
 FOR EACH ROW BEGIN

        IF NEW.sale_status <> OLD.sale_status THEN
            SET @changetype = 'Sale Status Updated';
        ELSE
            SET @changetype = 'Sale Edited';
        END IF;

        INSERT INTO sales_notification (sale_id, changetype, notify_to, old_value, new_value) VALUES (NEW.id, @changetype, NEW.submit_by, OLD.sale_status, NEW.sale_status);

    END$$

DELIMITER ;

0

该文档中提到:

OLD.col_name指的是在更新或删除之前,现有行中的一列。

因此,OLD.col_name仅适用于如下所示的UPDATEDELETE操作:

CREATE TRIGGER my_trigger
AFTER UPDATE ON test FOR EACH ROW
   -- ↑ Here
...

或者:

CREATE TRIGGER my_trigger
AFTER DELETE ON test FOR EACH ROW
   -- ↑ Here
...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接