2017-03-14 6 views
0

이 코드의 문제점이 어디 있는지 알 수 없기 때문에 도움이 필요한 사람이 필요합니다.패키지, 트리거 및 프로 시저가 정상적으로 작동하지 않습니다.

2 개의 테이블이 있습니다. 제품 (id, .., currentPrice) 및 가격 (id, product_id, 날짜, 가격). Prices.price의 값이 삽입, 업데이트 또는 삭제 될 때 Products.currentPrice의 값을 자동으로 업데이트하는 트리거 및 프로 시저를 만들어야합니다. 패키지, 두 개의 트리거 및 프로 시저를 만들고 모두 컴파일 할 수 있지만 확인, 삽입 또는 업데이트 또는 값을 삭제할 때 아무 일도 발생하지 않습니다. 그러나 수동으로 프로 시저를 호출하고 product_id (예 : 제품 테이블의 기존 제품에 대한 값 1)를 삽입 할 때마다 id 1 인 제품의 Products.currentPrice 값이 업데이트됩니다. BEFORE 트리거의 값이 PACKAGE 변수에 저장되지 않는다고 생각합니다. '데이터를 찾을 수 없음'오류가 발생했기 때문입니다. SQL Developer와 Oracle 11g XE를 사용하고 있습니다. 당신은 관련된 여기에 몇 가지를하고있는

CREATE OR REPLACE PACKAGE mypackage IS 
gid NUMBER; 
END; 


CREATE OR REPLACE TRIGGER trg_currentprice1 
BEFORE INSERT OR UPDATE OR DELETE ON prices 
FOR EACH ROW 
BEGIN 
    IF (INSERTING OR UPDATING) THEN 
    BEGIN 
     mypackage.gid := :new.product_id; 
    END; 
    ELSE 
    BEGIN 
     mypackage.gid := :old.product_id; 
    END; 
    END IF; 
END; 


CREATE OR REPLACE TRIGGER trg_currentprice2 
AFTER INSERT OR UPDATE OR DELETE ON prices 
DECLARE 
    v_id NUMBER := mypackage.gid; 
BEGIN 
    calc_currentprice(v_id); 
END; 


CREATE OR REPLACE PROCEDURE calc_currentprice(prodid IN NUMBER) AS 
    curprice Products.currentPrice%TYPE; 
    PRAGMA AUTONOMOUS_TRANSACTION; 
BEGIN 
    curprice := 0; 
SELECT price INTO curprice FROM prices 
WHERE product_id = prodid AND date = (SELECT MAX(date) FROM prices WHERE product_id = prodid AND date <= SYSDATE); 
EXECUTE IMMEDIATE 'ALTER TRIGGER trg_products_forbid2 DISABLE'; 
UPDATE products 
SET currentPrice = curprice 
WHERE product_id = prodid; 
EXECUTE IMMEDIATE 'ALTER TRIGGER trg_products_forbid2 ENABLE'; 
END; 
+0

해제와 동의 - 자율 거래를 사용해서는 안되며 여기에서 트리거를 변경해야합니다. 트리거를 변경하는 것이 글로벌 작업이며 현재 세션뿐 아니라 모든 세션에 영향을 미친다는 사실을 포함하지 않는 이유 중 하나입니다. –

답변

2

:

여기 내 코드입니다. 먼저 일련의 작업을 수행하기 위해 두 개의 트리거를 사용하려고합니다. 트리거 발사 순서는 보장되지 않습니다. 하나의 방아쇠로 다음을 고려하십시오.

CREATE OR REPLACE TRIGGER trg_currentprice1 
BEFORE INSERT OR UPDATE OR DELETE ON prices 
FOR EACH ROW 
BEGIN 
    IF (INSERTING OR UPDATING) THEN 
    BEGIN 
     calc_currentprice(:new.product_id); 
    END; 
    ELSE 
    BEGIN 
     calc_currentprice(:old.product_id); 
    END; 
    END IF; 
END; 

두 번째로, proc에서는 자치 트랜잭션을 지정하지만 사용자는 커밋하지 않습니다.

이제 코드가 도움이되지만 알아둬야 할 몇 가지 사항이 있습니다.

트리거와 함께 실행하지 않는 것이 좋습니다. 가격을 업데이트하는 PL/SQL 코드가있는 경우 코드를 포함하여 제품을 업데이트하십시오. 어쩌면 더 나은 점은 제품 레코드를 업데이트 할 필요없이 필요할 때마다 현재 제품의 가격을 조회 할 필요가 없도록 제품에서 가격을 분리 할 수 ​​있는지 여부입니다.

이와 같은 트리거 처리에는 커밋을 포함하지 마십시오. 사용자 트랜잭션이 커밋하지 않으면 더 이상 유효하지 않은 변경 내용을 커밋하지만 롤백 후에 존재하지 않는 가격으로 제품을 업데이트 할 수 있습니다.

코드 내에서 트리거를 사용하거나 사용하지 않도록 설정하지 마십시오. 이 작업을 수행해야하는 경우 설계에 결함이 있습니다.

코드 실행에 전역 변수를 사용하려고합니다. 이것은 또한 피해야합니다.

+0

필자는 PL/SQL에 익숙하지 않으며이 코드는 학습 목적으로해야 할 더 큰 과제 중 하나입니다. 나는 트리거와 절차를 사용해야합니다. 나는 당신이 나에게 말한 것을 읽었지만, 오라클 PL/SQL에서 나는 '멍청한 놈'이기 때문에 그것을 잘 읽지 못했습니다. 내가 당신의 말을 올바르게 받아들이면 커밋을 추가해야합니다. 두 번째 자율 트랜잭션 후 ... – MaliVragolan

+0

실제로 PRAGMA AUTONOMOUS TRANSACTION을 해당 proc에서 제거하고 다른 외부 procs 또는 proc 호출 중 하나에서 정상 트랜잭션으로 트랜잭션을 커밋해야합니다. – unleashed

+0

하지만 PRAGMA를 제거하면 제품의 currentPrice 필드를 업데이트 할 수 없습니다. 그 값을 변경하지 못하게하는 필수 트리거가 있기 때문입니다. 이 프로 시저를 호출 할 AFTER 트리거 내에서 PRAGMA를 이동할 수 있습니다. 그러나 슬픈 것처럼, 자신의 작품에 대한 절차가 있지만 패키지와 2 개의 방아쇠가 결합되어 있지 않으면 해결되지 않습니다. – MaliVragolan