4

私はトリガーにかなり慣れていないので、明らかにどこかで何か間違ったことをしています。元のテーブルからデータを取得するレポート テーブルに取り組んでいます。簡単にするために、1 つのテーブルと 1 つのレポート テーブルがあるとします。

元のテーブル (orig_tab)

CREATE TABLE orig_tab (
PK     NUMBER(8)       not null,
NAME   VARCHAR2(20)            ,
);

INSERT INTO orig_tab (PK, NAME) VALUES (1, 'AAA');
INSERT INTO orig_tab (PK, NAME) VALUES (2, 'BBB');
INSERT INTO orig_tab (PK, NAME) VALUES (3, 'CCC');

次に、レポート テーブル (rep_tab) があります。

CREATE TABLE rep_tab (
PK     NUMBER(8)       not null,
NAME   VARCHAR2(20)            ,
);

ここで、ユーザー インターフェイスから、誰かがレコード 2 の値を変更します。明らかに、これはレポート テーブルの挿入として扱われるべきです (このレコードは存在しないため)。その後、しばらくすると値が変更されるため、レポート テーブルの更新ケースになります。

質問: この種のトリガーを作成するにはどうすればよいですか? マージステートメントの場合だと思います。

これは私がやったことです:

create or replace trigger vr_reporting_trigger
after update on orig_tab
  for each row
begin
  MERGE INTO rep_tab d
  USING (SELECT pk FROM orig_tab) s
  ON (d.pk = s.pk)
  WHEN MATCHED THEN
  UPDATE SET d.pk = s.pk,
             d.name = s.name
  WHEN NOT MATCHED THEN
  INSERT (d.pk, d.name) VALUES (s.pk, s.name);
end vr_reporting_trigger;

それを理解するのに役立つ提案や推奨事項はありますか? ありがとう。

4

3 に答える 3

3

Merge ステートメントは計画のように聞こえますが、AFTER INSERT トリガーではなく AFTER UPDATE トリガーであると述べたため、最初の挿入時にトリガーが起動しない点が異なります。

また、Mutating table problemSELECT pk FROM orig_tabが発生します。

より良い方法は、 AFTER INSERT OR UPDATE トリガーを定義し、それを INSERT/UPDATING キーワードと組み合わせて挿入/更新を処理し、 :new/を使用:oldして新しいデータと古いデータをそれぞれ処理することです。

CREATE OR replace TRIGGER vr_reporting_trigger
  AFTER INSERT OR UPDATE ON orig_tab
  FOR EACH ROW
BEGIN
    IF inserting THEN
      INSERT INTO rep_tab
                  (pk,
                   name)
      VALUES      (:NEW.pk,
                   :NEW.name);
    ELSIF updating THEN
      UPDATE rep_tab r
      SET    name = :NEW.name
      WHERE  r.pk = :old.pk;
    END IF;
END vr_reporting_trigger; 
于 2012-06-21T10:02:00.283 に答える
3

以前の回答で処理されていないいくつかのまれなケースがあります。

行が挿入されたときに、一致する pk がレポート テーブルに既に存在する場合はどうなりますか。(通常、これが起こるとは考えていませんが、誰かが orig_tab から行を削除し、再度挿入した場合に何が起こるかを考えてみてください。(これは、テストではなく本番環境で発生する種類の問題です。今のうちに計画を立てた方がよいでしょう。)

BEGIN
   IF inserting THEN
      -- insure we avoid duplicate key exception with a NOT EXISTS predicate
      INSERT INTO rep_tab(pk,name)
      SELECT :new.pk, :new.name FROM DUAL
      WHERE NOT EXISTS (SELECT 1 FROM rep_tab WHERE pk = :new.pk);
      -- if row already existed, there's a possibility that name does not match
      UPDATE rep_tab t SET t.name = :new.name 
       WHERE t.pk = :new.pk;
      -- could improve efficiency of update by checking if update is actually
      -- needed using a nullsafe comparison ( t.name <=> :new.name );
   ELSIF updating THEN
      -- handle updates to pk value (note: the row to be updated may not exist
      -- so we need to fallthru to the merge)
      IF :new.pk <> :old.pk THEN
         UPDATE rep_tab t
            SET t.pk = :new.pk
              , t.name = :new.name
          WHERE t.pk = :old.pk ;
      END IF;
      MERGE INTO rep_tab d
      USING DUAL ON (d.pk = :old.pk)
      WHEN MATCHED THEN
      UPDATE SET d.name = :new.name
      WHEN NOT MATCHED THEN
      INSERT (d.pk,d.name) VALUES (:new.pk,:new.name);
   END IF;
END;
于 2012-06-22T22:47:57.133 に答える
1

これは、レコードが orrig_tab で更新され、rep_tab に対応するレコードがないかどうかについて尋ねられた拡張機能です。以下のロジックは、以下の要求に対応します。このソリューションは Sathya に属しているため、この回答で私を判断しないでくださいSathya AnswerJaanna

CREATE OR replace TRIGGER vr_reporting_trigger
  AFTER INSERT OR UPDATE ON orig_tab
  FOR EACH ROW
BEGIN
    IF inserting THEN
      INSERT INTO rep_tab
                  (pk,
                   name)
      VALUES      (:NEW.pk,
                   :NEW.name);
    ELSIF updating THEN
       MERGE INTO rep_tab d
          USING DUAL
       ON (d.pk =:OLD.pk)
       WHEN MATCHED THEN
         UPDATE SET d.name = :OLD.name            
       WHEN NOT MATCHED THEN
         INSERT (d.pk,d.name) VALUES (:OLD.PK,:NEW.PK );
    END IF;
END vr_reporting_trigger; 
于 2012-06-21T18:15:03.287 に答える