0

PL / SQLで別の表を更新するトリガーを作成しようとしていますが、問題が発生しています。(私はこれを読みましたが、あまり役に立ちません)。

これが私の状況です、私は2つのテーブルを言うことができます:

顧客テーブル

CustomerID番号主キー、ItemsDelivered番号

アイテム

CustomerID番号、ItemID番号、ItemDelivered Varchar(15)

誰かが注文すると、Itemsテーブルに次のような新しいレコードがあるとします。

| CustomerID | ItemID | ItemDelivered | 
|         1  |    1   |    False      |

誰かがItemDelivered列を「True」に更新するたびにItemsDeliveredカウンターを上げるトリガーが必要です。

create or replace Trigger UpdateDelivered  
   After Update On Items For
     Each Row 
Declare  
   Counter Customers.ItemsDelivered%Type; 
Begin
  If (:Old.ItemDelivered ='False' And :New.ItemDelivered='True') Then
     Select ItemsDelivered into Counter From Customers where CustomerdID =:New.CustomerID; 
     Update....
  end if; 
END;

これが私の問題です。ItemDelivered列のみが更新された場合、New.CustomerIDはありません。

更新したばかりの行のCustomerIDを取得する方法はありますか?(挿入された仮想テーブルで結合しようとしましたが、テーブルが存在しないというエラーが発生します)

4

2 に答える 2

3

の行レベル トリガーではUPDATE、 と の両方:new.customerID:old.customerID定義する必要があります。を更新しない限りCustomerID、2 つの値は同じになります。それを考えると、それはあなたが望むように聞こえます

create or replace Trigger UpdateDelivered  
   After Update On Items For
     Each Row 
Begin
  If (:Old.ItemDelivered ='False' And :New.ItemDelivered='True') Then
     Update Customers
        set itemsDelivered = itemsDelivered + 1
      where customerID = :new.customerID;
  end if; 
END;

とはいえ、この種のカウンターを格納し、それをトリガーで維持することは、一般に、データ モデルを設計する上で問題のある方法です。これは基本的な正規化に違反しており、あらゆる種類の競合状態につながる可能性があります。たとえばSELECT、元のカウントを取得してから更新を実行する場所を最初に示した方法でトリガーをコーディングすると、マルチユーザー環境でバグが発生します。配達済みのアイテムをマークすると、どちらのトランザクションも他のセッションの変更を認識せず、カウンターが間違った値に設定されます。また、バグのないコードを実装したとしても、シリアライゼーション メカニズムを導入する必要があります (この場合、CUSTOMERSテーブルの行レベル ロックは、UPDATE) これにより、異なるセッションが互いに待機する必要が生じます。これにより、アプリケーションのスケーラビリティとパフォーマンスが制限されます。

the:old.customerIDと the の:new.customerID両方が定義され、両方が等しいことを示すため

SQL> desc items
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 CUSTOMERID                                         NUMBER
 ITEMID                                             NUMBER
 ITEMDELIVERED                                      VARCHAR2(10)


SQL> ed
Wrote file afiedt.buf

  1  create or replace
  2  trigger updateDelivered
  3    after update on items
  4    for each row
  5  begin
  6    if( :old.itemDelivered = 'False' and :new.itemDelivered = 'True' )
  7    then
  8      dbms_output.put_line( 'New CustoerID = ' || :new.customerID );
  9      dbms_output.put_line( 'Old CustomerID = ' || :old.customerID );
 10    end if;
 11* end;
SQL> /

Trigger created.

SQL> select * from items;

CUSTOMERID     ITEMID ITEMDELIVE
---------- ---------- ----------
         1          1 False

SQL> update items
  2     set itemDelivered = 'True'
  3   where customerID = 1;
New CustoerID = 1
Old CustomerID = 1

1 row updated.
于 2012-04-06T17:19:24.480 に答える
1

アイテム数をデータベースに保存したい場合は、トリガーのペアをお勧めします。after row トリガーを使用してアイテム番号 (おそらくパッケージ内のテーブル変数) を記録し、after ステートメント トリガーを使用してカウンターを実際に更新し、基準日から直接配送されたアイテムを計算します。つまり、

select sum(itemsDelivered) from Customers where itemId = :itemId;

このようにして、カウンターを常にあるべき値に設定しているため、カウンターが破損する危険を回避できます。派生データを別のテーブルに保持することをお勧めします。

個別の「派生」テーブルのデータを更新するデータベース トリガーに完全に基づいて古いシステムを構築しましたが、非常にうまく機能しました。ビジネスルールを知らなくても、データベーステーブルを挿入、更新、削除するだけで、すべてのデータ操作を実行できるという利点がありました。たとえば、学生をクラスに入れるには、登録テーブルに行を挿入するだけで済みます。selectステートメントの後、授業料、手数料、財政援助、およびその他すべてがすでに計算されています。

于 2012-04-07T01:01:04.693 に答える