2015-03-02 29 views
1

好吧,我從課程中得到了一些練習練習,我發現了一個我無法弄清楚的問題,即使它聽起來很簡單。我有這張桌子。我想做一個觸發器,在每次更新或向產品表中插入一個值後,它會使用該類別的產品數量和價格總和更新類表。ORACLE SQL - 無法獲取觸發器以獲取正在更新的表中的總和/計數值

起初我嘗試使用FOR EACH ROW,但我無法弄清楚如何使它讀取產品表新產品值的新條目沒有'變異',因爲我正在嘗試讀取正在更新/插入的產品表。即使有一個正確的方法來設置:新的,也無法弄清楚。和:老。以此目的。

嘗試過檢查產品表並選擇變量和總和的遊標,但它是同樣的問題,整個「變異」問題。

現在我沒有了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); 

回答

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及時調用合併語句駐留在觸發器內,或者可以使用相同的調整方法。

+0

謝謝,沒有意識到這個合併函數。 – user2429212 2015-03-02 19:45:16

0

所以,你發現了突變。首先,如果你發現你需要處理突變,問問你自己爲什麼。我會懷疑數據模型或應用程序設計中存在缺陷。無論如何,說了這些,讓我們談一談突變以及如何避免它。

在觸發器代碼中有行級觸發器並引用構建觸發器的表時會發生突變,並且單個SQL語句影響表中的多行。 Oracle不知道如何保持一致性,因爲每一行都會重新執行觸發器。

處理突變的標準方法是編寫一個包,包含三個函數和一個包級數組。這三個函數是initialize(),save_row()和process()。

您需要三個步驟才能使其工作。首先,你需要一個語句級別的BEFORE觸發器來調用initialize()函數,以初始化一個包級數組。然後,行級別的BEFORE觸發器將調用save_row()函數,該函數將當前行(pk或rowid)保存到數組中,最後是一個statle級別的AFTER觸發器,以調用process()讀取數組中的行並相應地處理數據。

如果你去http://asktom.oracle.com/並尋找'表突變',你會發現很多回答問題,並附有示例代碼。

希望有所幫助。

+0

感謝您的解釋,我會檢查該網站了。 – user2429212 2015-03-02 19:45:33

相關問題