1

わかりました、クラスからいくつかの練習問題を受け取りましたが、非常に単純に聞こえますが、理解できないものを見つけました。私はこのテーブルを持っています。製品テーブルに値を更新または挿入するたびに、そのクラスに属する製品の数と価格の合計でクラス テーブルを更新するトリガーを作成したいと考えています。

最初はFOR EACH ROWを使ってみたのですが、商品を読み込もうとしていたので、新しいエントリのクラスの商品テーブルの新しい商品の値を「変異」せずに読み取るようにする方法がわかりませんでした。更新/挿入されていたテーブル。:new の正しい設定方法があったとしても、わかりませんでした。そして:古い。この目的のために。

製品テーブルをチェックし、カウントと合計の変数を選択するカーソルを試しましたが、それは同じ問題であり、「変異」の問題全体でした。

FOR EACH ROWなしで取得しましたが、すべてのクラスのすべての製品と価格をカウントして合計します。各クラスで個別に機能させる方法がわかりません。最大クラスに基づいて増加するループとカウンターかもしれませんが、それは複雑すぎるようです。どんな助けでも大歓迎です。

drop table class        cascade constraints;
drop table provider     cascade constraints;
drop table product      cascade constraints;


CREATE TABLE class(
class           number(5)       constraint  pk_class primary key,
description     varchar2(20)    constraint  nn1_class CHECK(description = INITCAP(description) AND description IS NOT NULL),
tot_product     number(5)       constraint  nn2_class CHECK (tot_product >=0  AND tot_product IS NOT NULL),
tot_price       number(12,2)    constraint  nn3_class CHECK (tot_price >=0  AND tot_price IS NOT NULL),
constraint      pk1_class       CHECK (class >=0)
);


INSERT INTO class VALUES(1,'Description 1', 0, 0);
INSERT INTO class VALUES(2,'Description 2', 0, 0);
INSERT INTO class VALUES(3,'Description 3', 0, 0);
INSERT INTO class VALUES(4,'Description 4', 0, 0);
INSERT INTO class VALUES(5,'Description 5', 0, 0);


CREATE TABLE provider(
provider    number(5)       constraint  pk_provider primary key,
description varchar2(20)    constraint  nn1_provider    CHECK(description = INITCAP(description) AND description IS NOT NULL),
constraint  pk1_provider    CHECK (provider >=0)
);

INSERT INTO provider VALUES(1,'Description 1');
INSERT INTO provider VALUES(2,'Description 2');
INSERT INTO provider VALUES(3,'Description 3');
INSERT INTO provider VALUES(4,'Description 4');
INSERT INTO provider VALUES(5,'Description 5');


CREATE TABLE product(
product         number(5)       constraint  pk_product      primary key,
description     varchar2(20)    constraint  nn1_product CHECK (description = INITCAP(description) AND description IS NOT NULL),
price           number(12,2)    constraint  nn2_product CHECK (price >=0        AND price   IS NOT NULL),
available       number(5)       constraint  nn3_product CHECK (available >=0    AND available IS NOT NULL),
class           number(5)       constraint  fk1_product     references class        NOT NULL,           
provider        number(5)       constraint  fk2_product references provider NOT NULL,   
constraint      pk1_product CHECK (product >=0)
);




CREATE OR REPLACE TRIGGER tot_class
AFTER INSERT OR UPDATE ON product

DECLARE
e_tot_product   number(5);  
e_tot_price     number(12,2);

BEGIN

SELECT COUNT(product) INTO e_tot_product
    FROM product
    WHERE class = class; 

SELECT SUM(price) INTO e_tot_price 
    FROM product
    WHERE class = class;


UPDATE class SET tot_product = e_tot_product, tot_price= e_tot_price WHERE class = class;
END;
/


INSERT INTO product VALUES(1,'Description 1', 100, 10, 1, 1);
INSERT INTO product VALUES(2,'Description 2', 100, 10, 1, 2);
INSERT INTO product VALUES(3,'Description 3', 100, 10, 2, 1);
INSERT INTO product VALUES(4,'Description 4', 100, 10, 4, 5);
INSERT INTO product VALUES(5,'Description 5', 100, 10, 2, 3);
4

2 に答える 2

0

MERGE以下のようにトリガーでステートメントを使用することをお勧めします

CREATE OR REPLACE TRIGGER TOT_CLASS
AFTER INSERT OR UPDATE
ON PRODUCT 
REFERENCING NEW AS NEW OLD AS OLD
BEGIN

MERGE INTO class oldclass
using 
( 
SELECT a.class,COUNT(b.product) tot_poduct,sum(b.price) tot_price
    FROM product b
    join
    class a
    on a.class = b.class
    group by a.class
)    newclass
on (oldclass.class = newclass.class)
when matched then 
update set oldclass.tot_product = newclass.tot_poduct,
oldclass.tot_price = newclass.tot_price;

END;
/

ここで製品クラスが更新された場合、古い製品数と合計価格も再確認する必要があります。したがって、上記のステートメントはそのような問題を取ります。それでも、大規模なデータセットでのパフォーマンスについてはわかりません。マージステートメントのタイムリーな呼び出しをトリガー内に配置するDBMS_JOBSか、同じ方法でチューニングメソッドを使用することをお勧めします。

于 2015-03-02T09:30:04.070 に答える
0

それで、あなたは突然変異を発見しました。まず、ミューテーションに対処する必要がある場合は、その理由を自問してください。データ モデルまたはアプリケーションの設計に問題があると思われます。ただし、そうは言っても、突然変異とそれを回避する方法について少し話しましょう。

ミューテーションは、行レベルのトリガーがあり、トリガー コードでトリガーが構築されているテーブルを参照しており、単一の SQL ステートメントがテーブル内の複数の行に影響を与えている場合に発生します。各行がトリガーを再実行するため、Oracle は一貫性を維持する方法を知りません。

ミューテーションを処理する標準的な方法は、3 つの関数とパッケージ レベルの配列を含むパッケージを作成することです。3 つの関数は、initialize()、save_row()、および process() です。

それを機能させるには、3 つのステップが必要です。まず、パッケージ レベルの配列を初期化するために、initialize() 関数を呼び出すステートメント レベルの BEFORE トリガーが必要です。次に、行レベルの BEFORE トリガーが save_row() 関数を呼び出して現在の行 (pk または rowid) を配列に保存し、最後に文レベルの AFTER トリガーで process() を呼び出して配列内の行を読み取り、それに応じてデータを処理します。

http://asktom.oracle.com/にアクセスして「テーブル ミューテーション」を検索すると、サンプル コードを含む多数の質問への回答が見つかります。

于 2015-03-02T08:59:19.403 に答える