1

大学の授業で SQL と DB の設計を学んでいます。私たちに与えられた課題の 1 つは、いくつかの子属性の合計である派生属性を持つテーブルを作成することです。例えば:

ORDERS
orderID {PK}
/orderTotal    /* derived from SUM of child itemTotals */

ITEMS
itemNo {PK}
orderID {FK}
itemTotal

今、これが良い習慣であるかどうかさえわかりません。私がウェブで行ったいくつかの読書から、導出された値は保存されるべきではなく、ユーザーアプリケーションによって計算されるべきです。その観点は理解できますが、この場合の私の任務は、派生した値を保存することであり、さらに重要なことに、トリガーを介してそれらの整合性を維持することです。これは私にとって比較的新しいものなので、それらを使用することを楽しんでいます。また、より複雑なケースでは、派生した値を保存するために処理時間を節約する価値があると想像します。問題を引き起こしていない、私が導入した保護手段は次のとおりです。

新しい子アイテムが挿入されたときに親 /orderTotal を更新するトリガー。

子アイテムが削除されたときに親 /orderTotal を更新するトリガー。

子 itemTotal が変更されたときに親 /orderTotal を更新するトリガー。

ただし、私が達成する方法がわからない別の保護手段が必要です。親属性 /orderTotal は派生しているため、手動で変更しないでください。誰かがそれを (実際には正しい SUM ではない誤った値に) 手動で変更しようとした場合、(a) 彼らがこれを行うのを防ぐか、(b) 変更が完了したらすぐに古い値に戻します。 .

どちらがより良いアプローチで、どちらが可能ですか (そしてどのように)? 前者を達成する方法がわかりません。トリガーまたは制約のいずれかを介して後者を達成しようとしましたが、どちらも適切ではないようでした。トリガーメソッドは、トリガーを起動したテーブルを変更しようとすると、ORA-04091 エラーを返し続けました。制約メソッドも、制約チェック内でそのような特定のことを行う方法がわからないため、適切ではないと思います。

ちなみに、SQL DeveloperでOracle SQLを使用しています。

ありがとう!

4

2 に答える 2

3

「今、これが良い習慣であるかどうかさえ確信が持てません。」

あなたの直感は正しいです。これ悪い習慣です。なんらかの理由で、多くの大学教授が学生に質の悪いコードを書くタスクを課しています。少なくとも、これは悪い習慣であり、現実の世界では決して使用すべきではないと説明されていれば、それほど悪くはありません。しかし、ほとんどの教授は、現実の世界で何が重要かについて、限られた理解しか持っていないと思います。 ため息

とにかく、あなたの質問に答えるために。これには 2 つのアプローチがあります。1 つは、トリガーを使用して「修正」することです。つまり、変更を飲み込みます。値を変更しようとするユーザーは、ビジネス ルールに違反していることに気づかずに、変更が適用されない理由を発見しようとして多くの時間を浪費する可能性があるため、これは誤りです。したがって、例外をスローする方がはるかに優れています。

この例では、Oracle の構文を使用しています。

create or replace trigger order_header_trg
    before insert or update
    on order_header for each row
begin
    if :new.order_total != :old.order_total
    then
        raise_application_error 
                 ( -20000, 'You are not allowed to modify the value of ORDER_TOTAL');
    end if;
end;

このアプローチの唯一の問題は、ORDER_LINES に行を挿入してから ORDER_HEADER の新しい合計を導き出すことができないことです。

これが、非正規化合計が悪い習慣である理由の 1 つです。

あなたが得ているエラー - ORA-04091 - は「テーブルを変更しています」と言います。これは、トリガーを所有するテーブルから選択するトリガーを作成しようとすると発生します。ほとんどの場合、不十分な正規化が行われた不十分なデータ モデルを示しています。これは明らかにここに当てはまります。

データ モデルに行き詰まっていることを考えると、唯一の回避策は、複数のトリガーとパッケージを使用した不格好な実装です。インターネットでは、わずかに異なるさまざまなソリューションが提供されています

于 2011-11-06T21:52:44.383 に答える
0

1 つの解決策は、を維持するためのすべてのロジックをテーブルorderTotalINSTEAD OF UPDATEトリガーに移動することです。ORDERS

すでに持っているトリガーは、計算を行わずITEMSに更新するように単純化できます- INSTEAD OF` トリガーを設定すると、更新ステートメントの代わりに実行されます。ORDERSorderTotal to 0 or something like that. The

注文合計を手動で更新しようとすると、INSTEAD OFトリガーが起動し、既存の値が再計算されます。

PS-テストするOracle DBはありませんが、私が知る限り、INSTEAD OFトリガーはORA-04091エラーを回避します-これが間違っている場合はお詫びします

EDIT このソリューションは他のRDBMSシステムでも機能しますが、OracleはINSTEAD OFビューのトリガーのみをサポートしています。

EDIT 2 割り当てで許可されている場合、ビューはこの問題の適切な解決策になる可能性があります。これにより、注文値列を計算できるようになるためです。

于 2011-11-06T07:40:38.717 に答える