5

次のテーブル構造があるとしましょう。

documents      docmentStatusHistory      status
+---------+   +--------------------+    +----------+
| docId   |   | docStatusHistoryId |    | statusId |
+---------+   +--------------------+    +----------+
| ...     |   | docId              |    | ...      |
+---------+   | statusId           |    +----------+
              | ...                |
              +--------------------+

明らかかもしれませんが、ドキュメントの現在のステータスが最後に入力されたステータス履歴であることは言及する価値があります。

システムのパフォーマンスはゆっくりではありますが確実に低下しているため、上記の構造を次のように変更することをお勧めします。

documents           docmentStatusHistory      status
+--------------+   +--------------------+    +----------+
| docId        |   | docStatusHistoryId |    | statusId |
+--------------+   +--------------------+    +----------+
| currStatusId |   | docId              |    | ...      |
| ...          |   | statusId           |    +----------+
+--------------+   | ...                |
                   +--------------------+

このようにして、ドキュメントの現在のステータスを本来あるべき場所に表示します。

レガシーアプリケーションの構築方法が原因で、ドキュメントテーブルの現在のステータスを更新するためにレガシーアプリケーションのコードを変更できませんでした。

この場合、従来のアプリケーションコードにアクセスできないという理由だけで、トリガーを回避するためにルールの例外を開く必要がありました。

ステータス履歴に新しいステータスが追加されるたびにドキュメントの現在のステータスを更新するトリガーを作成しました。これは魅力のように機能します。

ただし、あいまいでめったに使用されない状況では、単に新しいステータス履歴を追加するのではなく、最後のステータス履歴を削除する必要があります。そこで、次のトリガーを作成しました。

create or replace trigger trgD_History
 after delete on documentStatusHistory
 for each row
 currentStatusId number;
begin

  select statusId
    into currentStatusId
    from documentStatusHistory
   where docStatusHistoryId = (select max(docStatusHistoryId)
                                 from documentStatusHistory
                                where docId = :old.docId);

  update documentos
     set currStatusId = currentStatusId
   where docId = :old.docId;
end;

そして、それは私が悪名高いエラーを得たところORA-04091です。

トリガーをAFTERトリガーとして構成したのに、なぜこのエラーが発生するのか理解しています。

問題は、このエラーを回避する方法がわからないということです。私はしばらくの間ネットを検索しましたが、今のところ役立つものは何も見つかりませんでした。

やがて、Oracle9iを使用します。

4

2 に答える 2

9

ミューティングテーブルエラーの標準的な回避策は、次のように作成することです。

  • キーのコレクション(この場合はdocId)を含むパッケージ。一時的なテーブルも機能します
  • コレクションを初期化するbeforeステートメントトリガー
  • 変更された各docIdをコレクションに取り込む行レベルのトリガー
  • コレクションを反復処理して実際のUPDATEを実行するafterステートメントトリガー

だから何かのような

CREATE OR REPLACE PACKAGE pkg_document_status
AS
  TYPE typ_changed_docids IS TABLE OF documentos.docId%type;
  changed_docids typ_changed_docids := new typ_changed_docids ();

  <<other methods>>
END;

CREATE OR REPLACE TRIGGER trg_init_collection
  BEFORE DELETE ON documentStatusHistory
BEGIN
  pkg_document_status.changed_docids.delete();
END;

CREATE OR REPLACE TRIGGER trg_populate_collection
  BEFORE DELETE ON documentStatusHistory
  FOR EACH ROW
BEGIN
  pkg_document_status.changed_docids.extend();
  pkg_document_status.changed_docids( pkg_document_status.changed_docids.count() ) := :old.docId;
END;

CREATE OR REPLACE TRIGGER trg_use_collection
  AFTER DELETE ON documentStatusHistory
BEGIN
  FOR i IN 1 .. pkg_document_status.changed_docids.count()
  LOOP
    <<fix the current status for pkg_document_status.changed_docids(i) >>
  END LOOP;
  pkg_document_status.changed_docids.delete();
END;
于 2011-04-27T14:58:40.657 に答える
1

この質問の複製のようです

トム・カイトのそれに対する見解をチェックしてください

于 2011-04-27T14:54:25.787 に答える