oracle變異表觸發器相關問題解決

msdnchina發表於2009-08-17

今天遇到一個客戶的問題,問題是浪潮ps軟體(pb開發的c/s架構下的client端軟體)有一個核取方塊是預設"打鉤"的,而客戶這邊,根據業務的要求,這個核取方塊是不打鉤的,於是跟軟體開發工程師溝通了一下,開發工程師感覺這個不是通用需求,建議我用觸發器解決這個問題.我想了一下,感覺也可以.於是就自己弄了一個觸發器,如下:


CREATE OR REPLACE TRIGGER TRI_KCYXZ1_SFJCHZ
  BEFORE  update or insert on KCYXZ1
  for each row
   
declare PJLX varchar2(1);
begin
PJLX:=:NEW.KCYXZ1_PJLX;
IF (PJLX='M') THEN
         UPDATE KCYXZ1 SET
         KCYXZ1.KCYXZ1_SFJCHZ='0'
         WHERE  KCYXZ1_LSBH=:NEW.KCYXZ1_LSBH;

END IF;

end;

這個觸發器,在oracle中compile是沒有問題的,但是前臺軟體使用此表(KCYXZ1)對應的功能的時候,報錯(用sql monitor跟蹤如下):
----------------------------------
Timestamp: 09:01:38.265
update KCYXZ1 SET KCYXZ1_LSBH =KCYXZ1_LSBH WHERE KCYXZ1_LSBH =:1
:1 = '1053'
Runtime error occurred: 4091 (ORA-04091: 表 LC0039999.KCYXZ1 發生了變化, 觸發器/函式不能讀它
ORA-06512: 在 "LC0039999.TRI_KCYXZ1_SFJCHZ", line 7
ORA-04088: 觸發器 'LC0039999.TRI_KCYXZ1_SFJCHZ' 執行過程中出錯)
----------------------------------

從google.com上看了一下這個問題,發現這個是屬於變異表(mutating table)的觸發器的問題,詳細見如下帖子

http://blog.oracle.com.cn/html/58/t-120858.html

此貼子中有如下的描述,我感覺比較有意義,摘錄下來:

觸發器中的SQL語句不能:

讀取或更新觸發語句的任何變異表也包括觸發表本身,讀取或更新該觸發表的約束表的主鍵列、唯一性鍵列或外來鍵列但是如果需要也可以更新其他列。這些限制約束適用於所有行級觸發器。但有個特例就是如果INSERT隻影響一行記錄那麼定義在這行上的行級BEFORE和AFTER觸發器就不會將這個觸發表當作變異表。

有另外一個帖子說到:

觸發器可以包括任何合法的PL/sQL語句,假有以下例外
1.觸發器不可以執行COMMIT、ROLLBACK或SAVEPOINT語句,而且不可以呼叫執行這些語句之一的函式或過程。
2.觸發器不可以宣告long或LONG RAW變數。
3.觸發器不可以在定義它的表上執行DML操作。

我自己寫的這個觸發器恰恰就違反了"3.觸發器不可以在定義它的表上執行DML操作"這個條件.

於是諮詢了一下開發工程師,並且在http://www.cnblogs.com/luyongqun/archive/2007/11/19/964470.html帖子的啟發下,採用直接賦值的方式,避免了使用update 等dml語句,巧妙的達到了目的.

改後的觸發器為(粗體藍字的為修改了的語句):

CREATE OR REPLACE TRIGGER TRI_KCYXZ1_SFJCHZ
  BEFORE  update or insert on KCYXZ1
  for each row

declare PJLX varchar2(1);
begin
PJLX:=:NEW.KCYXZ1_PJLX;
IF (PJLX='M') THEN
:NEW.KCYXZ1_SFJCHZ:='0';

END IF;

end;

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/161195/viewspace-612520/,如需轉載,請註明出處,否則將追究法律責任。

相關文章