在資料庫的觸發器中經常會用到更新前的值和更新後的值,所有要了解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在用于取值?因為指派沒意義?