3

これは、Web アプリケーションでは非常に一般的なことです。ユーザー テーブルがあり、ユーザー テーブルに加えられたすべての変更を追跡したい場合は、データベースの挿入トリガーと更新トリガーを使用して、それらの変更を user_history テーブルに保存できます。

しかし、 user_id 、 product_id 、 cost がある user_products テーブルがある場合はどうでしょうか。システムにユーザーを追加すると、そのユーザーに関連付けられた 2 つの製品があるとします。したがって、私の user_products テーブルには、そのユーザーの 2 つの行があります。

user_id product_id cost
1       10         1000
2       20         2000

ここで、ユーザーの編集ページに移動して製品 1 を削除し、製品 3 を追加して、製品 2 のコストを 2000 から 3000 に変更するとします。

したがって、通常は user_id 1 のすべてのレコードを user_product テーブルから削除してから、新しい製品の新しい挿入を行います。

したがって、通常の更新ではなく、削除してから挿入します。したがって、履歴の変更を追跡することはできません。

理想的には、製品 1 を削除し、製品 3 を追加し、製品 2 のコストを 2000 から 3000 に変更したことを知りたいと思います。

編集1:-

アップデートはしていません。削除してから挿入しています。そのため、製品 ID 2 でコスト 2000 のレコードを削除しています。次に、製品 ID 2 でコスト 3000 のレコードを再度挿入しています。技術的には削除と挿入ですが、論理的にはコストのみが 2000 から 3000 に変更されます。両方の実行中に確認した場合ID 2 の製品を削除してから、同じ ID 2 の製品を追加したというクエリが表示されます。しかし、コストが2000から3000に変化したことを確認できるようにしたい

4

2 に答える 2

4

1 つのオプションはuser_product_history、トリガーによって入力されるテーブルを作成してから、履歴テーブルの古い「削除」行をその後行が挿入さuser_productれた場合に変換するトリガーを定義することです。update

CREATE TABLE user_product_history (
  user_id         number,
  product_id      number,
  cost            number,
  operation_type  varchar2(1),
  operation_date  date
);

CREATE TRIGGER trg_user_product_history
  AFTER INSERT OR UPDATE OR DELETE ON user_product
  FOR EACH ROW
DECLARE 
  l_cnt integer;
BEGIN
  IF( deleting )
  THEN
    insert into user_product_history( user_id, product_id, cost, operation_type, operation_date )
      values( :old.user_id, :old.product_id, :old.cost, 'D', sysdate );
  ELSIF( updating )
  THEN
    insert into user_product_history( user_id, product_id, cost, operation_type, operation_date )
      values( :new.user_id, :new.product_id, :new.cost, 'U', sysdate );
  ELSIF( inserting )
  THEN
    select count(*)
      into l_cnt
      from user_product_history
     where operation_type = 'D' 
       and user_id        = :new.user_id
       and product_id     = :new.product_id;
    if( l_cnt > 0 )
    then
      update user_product_history
         set operation_type = 'U',
             operation_date = sysdate,
             cost           = :new.cost
       where operation_type = 'D' 
         and user_id        = :new.user_id
         and product_id     = :new.product_id;
    else
      insert into user_product_history( user_id, product_id, cost, operation_type, operation_date )
        values( :new.user_id, :new.product_id, :new.cost, 'I', sysdate );
    end if;
  END IF;
END;

ただし、効率の観点からすると、更新ではなく削除と挿入を行うと、データベースに必要以上の負荷をかけることになります。必要以上に多くの I/O を行うことになります。そして、変更を処理するためのはるかに複雑なコードになってしまいます。ほぼ確実に、何が変更されたかを把握してから、それらの行を更新する方が適切です。

于 2012-04-10T03:47:51.420 に答える
1

「標準的な」方法か単純な方法かはわかりませんが、私の経験では、自分で行う必要があります...もちろん、テーブルごとに特定のメソッドをコーディングする必要はありませんが、一般的なメソッドですすべての更新 SQL を処理します。これは、テーブル構造に応じたスマートなものです。例: 以下を持つ履歴テーブルを定義できます: id - テーブル名 - テーブル レコード ID - 更新するフィールドのリスト - 更新前の値のリスト - 更新後の値のリスト

次に、コードに、SQL クエリを処理する抽象クラスを含める必要があります。更新時に、SQL クエリを解析してこのテーブルにレコードを挿入するメソッドを呼び出します。更新前のデータ (SELECT はほとんどリソースを使用せず、DB サーバー キャッシュを使用できるため、オーバーヘッドは最小になります)。最後に、レコード (ユーザーなど) に関連する情報を表示する場合、このテーブルとこのユーザー ID の履歴を表示するコードを追加できます。

それがあなたを助けることを願っています。

于 2012-04-10T03:41:23.803 に答える