2017-08-17 1 views
0

現在、私はテンプレートのいくつかの関連テーブルにいくつかの行を作成するプロシージャを実装しています。したがって、私のプロシージャはSAVEPOINTと、異なるテーブルにあるINSERTステートメントと、新しく作成された主キーを参照しながら他のテーブルにいくつかの行を挿入するためのCursorで構成されています。ネストされたBEFORE INSERT/UPDATEトリガーでのアトミックトランザクション

これらのテーブルは、それぞれに目的がある定義されたBEFORE INSERT/UPDATEトリガーがあります。

  • それがINSERT文で定義されていない場合は、シーケンサからの新しい主キーを取得します(がある場合はどこに彼らはNULL
  • 設定監査フィールド(last_change_date、last_change_user、等。)
いる場合、私はいくつかのデフォルト値を設定し
  • )同じトランザクションに後でそれを参照するように明示的に主キーを設定する必要があります

    トランザクションがORA-04091で失敗します。表には、変異され、トリガー/関数はそれを

    が表示されないことがあり、私は、各トリガーにPRAGMA自律型トランザクションを宣言することで、この問題を回避できることを、理解していますが、私のトランザクションだろうそれらのデータセット全体を作成/挿入する必要があるという要件であるため、これ以上原子的ではありません。

    私は自分のデータベースの設計において何が間違っていますか?


    UPDATE:これは、あなたがこのようなことが、よりコンパクト書くことができますトリガ

    CREATE TRIGGER TRG_AUFTRAG_B_IU 
        BEFORE INSERT OR UPDATE 
        ON AUFTRAG 
        FOR EACH ROW 
        BEGIN 
        IF INSERTING THEN 
        IF :new.id is NULL or :new.id = 0 THEN 
         SELECT SEQ_AUFTRAG.nextval into :new.id from dual; 
        END IF; 
    
        IF :new.nummer is NULL or :new.nummer = 0 THEN 
         SELECT nvl(MAX(NUMMER),0)+1 INTO :new.nummer FROM AUFTRAG WHERE EXTRACT(YEAR from DATUM) = EXTRACT(YEAR from :new.DATUM); 
        END IF; 
    
        --DEFAULT Values 
        IF :new.BETR_GRENZWERTE_RELEVANT is NULL THEN 
         SELECT 0 INTO :new.BETR_GRENZWERTE_RELEVANT FROM dual; 
        END IF; 
    
        IF :new.DOKUMENTE_ABGELEGT is NULL THEN 
         SELECT 0 INTO :new.DOKUMENTE_ABGELEGT FROM dual; 
        END IF; 
    
        IF :new.EXT_ORG is NULL or :new.EXT_ORG < 1 THEN 
         SELECT 1 INTO :new.EXT_ORG FROM dual; 
        END IF; 
    
        :new.ERSTELLT_VON := nvl(:new.ERSTELLT_VON,user); 
        :new.ERSTELLT_DATUM := nvl(:new.ERSTELLT_DATUM,sysdate); 
        END IF; 
    
        :new.GEAENDERT_VON := user; 
        :new.GEAENDERT_DATUM := sysdate; 
        END; 
    
  • +2

    トリガーのコードを表示してください。実際には、あなたが挙げた行動は非常に典型的でトリガーに役立ちますが、問題なく動作するはずです。 –

    +2

    トリガー内の同じテーブルから 'select'を実行しているようです。引き金が必要としていることに基づいて、「選択」の必要はありません。そして、あなたは正しいのです。「プラグマ自律型トランザクション」は、この種の問題に対する解決策ではありません。 –

    +1

    ああ!私はすでに問題が何かを見ていると思う....それは:新しい:NUMMERの部分ではないですか?これは、ビジネス要件である識別番号を作成するためのものです。それは、後にINSERT TRIGGERでこれを行うための解決策でしょうか? –

    答えて

    1

    のコードです:

    CREATE TRIGGER TRG_AUFTRAG_B_IU 
        BEFORE INSERT OR UPDATE 
        ON AUFTRAG 
        FOR EACH ROW 
        BEGIN 
        IF INSERTING THEN 
         :new.id = NVL(NULLIF(:new.id, 0), SEQ_AUFTRAG.nextval); 
    
         --DEFAULT Values 
         :new.BETR_GRENZWERTE_RELEVANT := NVL(:new.BETR_GRENZWERTE_RELEVANT, 0); 
         :new.DOKUMENTE_ABGELEGT := NVL(:new.DOKUMENTE_ABGELEGT, 0); 
    
         IF :new.EXT_ORG is NULL or :new.EXT_ORG < 1 THEN 
          :new.EXT_ORG := 1; 
         END IF;  
         :new.ERSTELLT_VON := nvl(:new.ERSTELLT_VON,user); 
         :new.ERSTELLT_DATUM := nvl(:new.ERSTELLT_DATUM,sysdate); 
        END IF; 
    
        :new.GEAENDERT_VON := user; 
        :new.GEAENDERT_DATUM := sysdate; 
    END; 
    

    のみ "の問題は、" この部分

    です
    IF :new.nummer is NULL or :new.nummer = 0 THEN 
        SELECT nvl(MAX(NUMMER),0)+1 INTO :new.nummer 
        FROM AUFTRAG 
        WHERE EXTRACT(YEAR from DATUM) = EXTRACT(YEAR from :new.DATUM); 
    END IF; 
    

    このプロシージャは、プロシージャまたはステートメントトリガー(つまり、 FOR EACH ROW句なし)

    CREATE TRIGGER TRG_AUFTRAG_B_A 
        AFTER INSERT ON AUFTRAG 
    BEGIN 
        UPDATE 
         (SELECT ID, NUMMER, 
          ROW_NUMBER() OVER (PARTITION BY EXTRACT(YEAR from DATUM) ORDER BY ID) as N 
         FROM AUFTRAG) 
        SET NUMMER = N 
        WHERE NUMMER IS NULL;   
    END; 
    
    +0

    ありがとう!これらの概念を変えること(表の変更)だけでなく、コードの改善を提案することもできます。 –

    関連する問題