2017-07-11 1 views
-1

挿入用にテーブルにトリガーを作成しようとしています。ここで作成スクリプトは次のとおりです。挿入用のトリガーを作成できないように見える - Oracle

CREATE OR REPLACE TRIGGER INTEG_QRY_NEW 
AFTER INSERT 
    ON INTEG_LOG 
    FOR EACH ROW 

DECLARE 
VAR2 NUMBER(10); 
LOG_TEXT1 VARCHAR2(1000); 
RESULT1 VARCHAR2(1000); 
QUERY_NUM1 VARCHAR2(1000); 
QUERY_TIME1 VARCHAR2(1000); 
LOG_INDEX1 NUMBER(10); 

BEGIN 
    SELECT COUNT(*) INTO VAR2 FROM USER_TAB_COLS WHERE (COLUMN_NAME = 'RESULT' OR COLUMN_NAME = 'QUERY_NUM' OR COLUMN_NAME = 'DATE_TIME') AND TABLE_NAME = 'INTEG_LOG'; 
    IF VAR2=0 THEN 
     EXECUTE IMMEDIATE 'ALTER TABLE INTEG_LOG ADD RESULT VARCHAR2(50); ALTER TABLE INTEG_LOG ADD DATE_TIME DATE; ALTER TABLE INTEG_LOG ADD QUERY_NUM VARCHAR2(50);'; 
    END IF; 

    LOG_TEXT1 := :NEW.LOG_TEXT; 
    QUERY_TIME1 := :NEW.QUERY_TIME; 
    LOG_INDEX1 := :NEW.LOG_INDEX; 

    IF QUERY_TIME1 = '' THEN 
     RESULT1 := '-1'; 
     QUERY_NUM1 := ''; 

     UPDATE INTEG_LOG 
     SET RESULT = RESULT1, 
       DATE_TIME = CURRENT_DATE, 
       QUERY_NUM = QUERY_NUM1 
     WHERE LOG_INDEX = LOG_INDEX1; 
    ELSE 
     RESULT1 := SUBSTR(LOG_TEXT1,(INSTR(LOG_TEXT1,'Result = ')+9),9); 
     QUERY_NUM1 := SUBSTR(SUBSTR(LOG_TEXT1,INSTR(LOG_TEXT1,'Q# ')+3,20),1,INSTR(SUBSTR(LOG_TEXT1,INSTR(LOG_TEXT1,'Q# ')+3,20),' ')); 

     UPDATE INTEG_LOG 
     SET RESULT = RESULT1, 
       DATE_TIME = CURRENT_DATE, 
       QUERY_NUM = QUERY_NUM1 
     WHERE LOG_INDEX = LOG_INDEX1; 
    END IF; 
END; 
/
トリガが(アプリケーションから来ている)次の列のための定期的なインサートの世話をしている
  1. LOG_DATEのNUMBER(10)、

    LOG_TIME番号(10)、

    LOG_TYPE番号(10)、

    LOG _TEXT VARCHAR2(2000 BYTE)、

    LOG_INDEX番号(10)、

    QUERY_TIME VARCHAR2(8バイト)の

  2. が存在するか否かを次の列のトリガチェックを(そうでない場合、それを)それらを追加します。 RESULT VARCHAR2(50 BYTE)、 DATE_TIMEのDATE、 QUERY_NUM VARCHAR2(50 BYTE)

  3. は、今では(LOG_TEXT列)文字列を取り、その結果の値とクエリ数を撤回された(後に来るもの'#Q')。
  4. 次に、同じ挿入方法を更新し、これらの値を新しい3列(result、date_timeおよびquery_num)に追加するだけです。私はテーブルに(INTEG_LOG)を挿入しようとしていたときに

トリガーが正常に作成されますんが、問題がある、私は次のエラーを取得する:

table string.string is mutating, trigger/function may not see it

Cause: A trigger (or a user defined plsql function that is referenced in this statement) attempted to look at (or modify) a table that was in the middle of being modified by the statement which fired it.

Action: Rewrite the trigger (or function) so it does not read that table.

これは構文エラーの可能性がありますか?助けてください。ありがとうございました。

+2

そのテーブルで起動するトリガ内のテーブルに列を追加することはできません。 トリガー内のどのテーブルにも列を追加しないでください。私はそれが良いアイデアとなるユースケースを考えることはできません。 – Allan

答えて

4

INTEG_LOGに動的SQLが追加しようとしている列がすでにあるため、トリガーをコンパイルする唯一の理由があります。テーブルにこれらの列がない場合、トリガーはそれらのUPDATEステートメントがコンパイルされないため無効であるため、トリガーはそれらを追加しません。

動的SQLを避けるべき理由の1つは、コンパイルエラーをランタイムエラーに変えることです。

しかし、そのテーブルに作成されたトリガ内のテーブルに列を追加しようとすると、驚くほど悪い考えです。 DDLステートメントは暗黙のコミットを発行し、トリガーをコミットすることはできません。これは、トランザクションで大混乱を招くためです。 (はい、pragma autonomous_transactionがありますが、それは通常コードのにおいです)。

正しい解決策は次のとおりです。

  1. が必要な場合はALTERを実行する前に、これらの列の前に存在を確認することで、スクリプトの冪等を行い、それらの列
  2. を追加するワンオフ DDLスクリプトを書きますTABLEステートメント
  3. スクリプトを実行します。
  4. テーブルにすべての列を設定します。

もちろん、これはこれらのUPDATEステートメントのためにである変異テーブルのエラーとは関係ありません。トリガーをホストしているテーブルでDML(selectを含む)を実行することはできません。どのビジネスルールを実装しようとしているのかは分かりませんが、別の方法でそれを行う必要があります。

関連する問題