天天看點

對資料庫觸發器new和old的了解

在資料庫的觸發器中經常會用到更新前的值和更新後的值,所有要了解new和old的作用很重要。當時我有個情況是這樣的:我要插入一行資料,在行要去其他表中獲得一個單價,然後和這行的資料進行相乘的到總金額,将該行的金額替換成相乘的結果。

一開始我使用的after,然後對自身的值進行更改。

insert update delete
old null 實際值
new

在Oracle中用

:old

:new

表示執行前的行,和執行後的行。在MySQL中用

old

new

表示執行前和執行後的資料。

問題的起源

之前對資料庫的觸發器是這樣寫的,

1 CREATE TRIGGER triggerName after insert ON consumeinfo
2     FOR EACH ROW
3     BEGIN
4       UPDATE consumeinfo SET new.金額=0;
5     END;      

觸發器建立沒問題,但是插入資料出現以下錯誤。

[Err] 1442 - Can't update table 'consumeinfo' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.      

但是通過上網搜尋的結果說對本表進行修改不用使用

update consumeinfo

,直接使用

SET new.金額=0

。這個做法對的,因為這樣使用new先對目前的金額改變了,然後存到資料庫中的,不用使用update consumeinfo。

經過一番努力,以下是成功後的代碼,貼出來看看

CREATE TRIGGER addnewReco BEFORE INSERT ON consumeinfo FOR EACH ROW
BEGIN
SET new.金額 = (
    SELECT `單價`
    FROM pricenow
    WHERE `類型` = new.類型
    ) * new.數量;
END;      

後來在吃飯打湯喝的時候突然想到new和old在after和before上使用情況不同。其實還是因為new不能在after進行指派,隻能進行讀取,複制要在before時指派。

new和old的使用情況

下面具體說說old和new的使用情況。在對new指派的時候隻能在觸發器before中隻用,在after中是不能使用的,比如(以下是正确的)。

CREATE TRIGGER updateprice
BEFORE insert
ON consumeinfo
FOR EACH ROW
BEGIN
   set new.金額=0;
END;      

這個說明對目前插入資料進行更新的時候使用before先更新完,然後才插入到資料庫中的,在after的觸發器中,new的指派已經結束了,隻能讀取内容。 如果使用after不能使用new指派,隻能取值,否則會出錯誤,比如

1 CREATE TRIGGER updateprice
2 AFTER insert
3 ON consumeinfo
4 FOR EACH ROW
5 BEGIN
6     set new.金額=0;
7 END;      

出現這樣的錯誤:

[Err] 1362 - Updating of NEW row is not allowed in after trigger      

總結:new在before觸發器中指派,取值;在after觸發器中取值。old在用于取值?因為指派沒意義?

繼續閱讀