0

2 つのテーブルを作成しました: INFORMATIONAND FEED

INFORMATION has 2 attributes : ID(Primary Key), TOT_AMOUNT.

FEED has 4 attributes : ID(Foreign key refer INFORMATION(ID)), S_AMOUNT, S_DATE, TOT_REM.

TOT_REMここで、 との挿入/削除/更新に基づいて、へ/から値を挿入/更新/削除する必要がS_AMOUNTありTOT_AMOUNTます。

サンプルの内容は次のとおりです。

INFORMATION Table
------------------
ID   |  TOT_AMOUNT
1    |    100
2    |    20
3    |    50
...

               FEED Table
----------------------------------------
ID   |   S_AMOUNT   |  S_DATE  | TOT_REM 
1    |     10       |10.10.2010|   90
1    |     10       |13.10.2010|   80
1    |     30       |17.10.2013|   50
1    |     10       |20.10.2016|   40
...

&の助けを借りて、 でTOT_REM実行された更新/挿入/削除操作に基づいて、属性に値を自動的に挿入する必要があります。S_AMOUNTTOT_AMOUNTS_AMOUNT

いつでも、TOT_REM を 0 未満にすることはできません。また、TOT_REM は自動的に挿入/削除/更新する必要があります。

TOT_REM for i(at a specific date) = (TOT_AMOUNT for ID=i) - 
                                    SUM(S_AMOUNT of all instances of ID=i,
                                    which is later than the S_DATE for ID=i); 

したがって、2 番目のタプル (1,10,'13.10.2010',80) を削除すると、反映された状態は次のようにBR_FEEDなります。

               FEED Table
----------------------------------------
ID   |   S_AMOUNT   |  S_DATE  | TOT_REM 
1    |     10       |10.10.2010|   90
1    |     30       |17.10.2013|   60
1    |     10       |20.10.2016|   50
...

表示に失敗するトリガーを作成しました

ORA-04091: table SSUMAN.FEED is mutating, trigger/function may not see it

トリガーのコードは次のとおりです。

CREATE OR REPLACE TRIGGER BR_INSERT_TRB
AFTER DELETE OR INSERT OR UPDATE OF S_AMOUNT ON FEED
FOR EACH ROW
BEGIN

IF DELETING THEN 
UPDATE  FEED bf
SET     bf.TOT_REM = bf.S_AMOUNT + :OLD.S_AMOUNT;
END IF;

IF INSERTING THEN 
INSERT INTO FEED (TOT_REM) VALUES(
((SELECT TOT_AMOUNT FROM INFORMATION bi WHERE bi.ID=:NEW.ID) - 
(SELECT SUM(S_AMOUNT) FROM FEED bf where bf.ID=:NEW.ID) - 
:NEW.S_AMOUNT);
END IF;

IF UPDATING THEN 
UPDATE  FEED bf
SET     bf.TOT_REM = (SELECT TOT_AMOUNT FROM BR_INFORMATION bi WHERE bi.ID=bf.ID) - 
(SELECT SUM(S_AMOUNT) FROM FEED bf where bf.ID=:NEW.ID) - 
 :NEW.S_AMOUNT
WHERE   :NEW.ID IS NOT NULL;
END IF;   

END;

質問:

  1. このアプローチは欠陥がありますか? この方法では、私が望むものを達成することはできませんか?[オプション]
  2. ここにビューを表示する範囲はありますか? 私はその線で考えることができません!おそらく、経験不足...[オプション]
  3. TOT_REM 値を自動的に反映できるようにするためのより良いアプローチはありますか?[回答必須]
4

2 に答える 2

1

これが私のビジネス上の問題であり、ゼロから始めることができる場合 (これはあなたのケースでは不可能かもしれません)、INFORMATIONテーブルをそのままにして、TOT_REMから列を削除しFEED、次のようなビューを作成します。現在のFEEDテーブル。ビュー定義に必要なすべてのロジックを記述できます。

追加:

まず、ビューの定義を次に示します。ベーステーブルINFORMATIONを想定してFEEDおり、OPで説明されているとおりで、TOT_REM列はありませんFEED

create view remaining_balance (id, s_amount, s_date, tot_rem) as
select i.id, f.s_amount, f.s_date, 
       i.tot_amount - nvl(sum(f.s_amount) over (partition by f.id order by f.s_date), 0)
from   information i left outer join feed f
                     on i.id = f.id
;

ビューは外部結合を使用して、 に対応する行がないテーブルidのを含めます。(次に、 の計算で null を処理するために、関数を使用して に変換します。)INFORMATIONFEEDTOT_REMnvl()NULL0

ビューを実行する例を次に示します。

 SQL> select * from information;

        ID TOT_AMOUNT
---------- ----------
         1        100
         2         20
         3         50

3 rows selected.

SQL> select * from feed;

        ID   S_AMOUNT S_DATE
---------- ---------- ----------
         1         10 2010-10-10
         1         10 2010-10-13
         1         30 2010-10-17
         1         10 2016-10-20

4 rows selected.

SQL> select * from remaining_balance order by id, s_date;

        ID   S_AMOUNT S_DATE        TOT_REM
---------- ---------- ---------- ----------
         1         10 2010-10-10         90
         1         10 2010-10-13         80
         1         30 2010-10-17         50
         1         10 2016-10-20         40
         2                               20
         3                               50

6 rows selected.

現在、複雑な制約を適用するための確立された方法は、具体化されたビューを使用することです。完全なチェック制約は行レベルでのみ機能し、条件が複数のテーブルに関係する場合は使用できません。現在の問題では、チェックは 2 つのテーブルに対して行われ、テーブルTOT_REM内の他の行に依存しているFEEDため、テーブル内の制約はいずれにしFEEDても機能しません。

マテリアライズド ビューのアプローチは、私が作成したようなビューをマテリアライズド ビューとして定義し、それを使用して定義しrefresh fast on commit(ベース テーブルでの DML 操作の直後に制約がチェックされるようにするため)、マテリアライズド ビューにチェック制約を作成することです。見る。当面の問題では、それは のチェックになりTOT_RM >= 0ます。

残念ながらrefresh fast on commit、ビュー定義が分析関数を使用する場合、禁止されています (少なくとも、私が持っている Oracle バージョン 11.2 と同じくらい最近)。関数の分析バージョンを使用したsum()ため、これは機能しません。

ただし、以下のように別の具体化されたビューを定義することは理にかなっているようです。

create materialized view remaining_balance (id, tot_rem) as
select i.id, i.tot_amount - f.sum_s_amount
from   information i inner join (select   id, sum(s_amount) as sum_s_amount 
                                 from     feed 
                                 group by id) f
                     on i.id = f.id
;

SQL> select * from remaining_balance;

        ID    TOT_REM
---------- ----------
         1         40

これは残りの残高のみを表示することになっているため、外部結合はもう使用しません。負でないことを確認するためINFORMATIONのチェック制約があり、 inがinを指す主キーであるため、このバージョンのビューの外部結合によって明らかにされる追加情報はありません。(ただし、必要に応じて、すべての を含めるようにすることもできます)。TOT_AMOUNTidFEEDidINFORMATIONid

refresh fast on commitここで、 でビューを定義し、 の効果にチェック制約を追加できるはずですtot_rem >= 0。残念ながら、私はそれをテストすることができません。高度なレプリケーション (実体化されたビュー ログを作成するために必要であり、これは に必要ですrefresh fast) は、私が持っている Oracle の無料の Express バージョンでは利用できない/有効になっていません。ただし、これを試してみてください-必要な解決策になる場合があります。幸運を!

于 2016-07-21T14:24:54.657 に答える