2017-04-23 16 views
1

오라클에 4 개의 테이블이 있습니다. hotel, tourist, stay, leave입니다. stay 테이블은 호텔에 머물러있는 관광객을 말하며, leave 테이블은 관광객이 호텔을 떠난 날짜의 정보를 저장합니다.동시 트리거를 사용하면 삽입 및 업데이트가 어려워집니다.

CREATE TABLE hotel (
    id NUMBER(5), 
    name VARCHAR2(50), 
    tenants_amount NUMBER(3) 
); 

ALTER TABLE hotel ADD CONSTRAINT hotel_c1 
CHECK(tenants_amount>=0 AND tenants_amount<=100); 

CREATE TABLE tourist (
    id NUMBER(5), 
    name VARCHAR2(50) 
); 

CREATE TABLE stay (
    tourist_id NUMBER(5), 
    hotel_id NUMBER(5) 
); 

CREATE TABLE leave (
    departure_date DATE, 
    hotel_id NUMBER(5), 
    tourist_id NUMBER(5) 
); 

내가 hotel에 삽입 또는 업데이트의 tenants_amount 테이블 stay의 내용과 일치하는지 확인에 관심이 있어요, 그래서 hotel

CREATE OR REPLACE TRIGGER hotel_trg 
BEFORE INSERT OR UPDATE ON hotel 
FOR EACH ROW 
DECLARE 
    amount NUMBER(3); 
BEGIN 
    SELECT COUNT(tourist_id) INTO amount FROM stay WHERE hotel_id=:NEW.id GROUP BY hotel_id; 
    IF :NEW.tenants_amount!=amount THEN 
     RAISE_APPLICATION_ERROR(-20001, 'Specified tenants amount differs from the system records'); 
    END IF; 
EXCEPTION 
    WHEN NO_DATA_FOUND THEN 
     IF :NEW.tenants_amount!=0 THEN 
      RAISE_APPLICATION_ERROR(-20001, 'Specified tenants amount differs from the system records'); 
     END IF; 
END; 
/

이 트리거를 쓴 나는 또한 쓴 leave의 정보 및 tenants_amount 속성의 관리를 저장하기위한 제 2 트리거는 hotel이다. 이

CREATE OR REPLACE TRIGGER stay_trg 
BEFORE INSERT OR UPDATE OR DELETE ON stay 
FOR EACH ROW 
DECLARE 
    amount NUMBER(3); 
BEGIN 
    IF INSERTING THEN 
     SELECT tenants_amount INTO amount FROM hotel WHERE id=:NEW.hotel_id; 
     UPDATE hotel SET tenants_amount=amount+1 WHERE id=:NEW.hotel_id; 
    END IF; 
    IF UPDATING AND :NEW.hotel_id!=:OLD.hotel_id THEN 
     SELECT tenants_amount INTO amount FROM hotel WHERE id=:OLD.hotel_id; 
     UPDATE hotel SET tenants_amount=amount-1 WHERE id=:OLD.hotel_id; 
     INSERT INTO leave VALUES (SYSDATE, :OLD.hotel_id, :OLD.tourist_id); 
     SELECT tenants_amount INTO amount FROM hotel WHERE id=:NEW.hotel_id; 
     UPDATE hotel SET tenants_amount=amount+1 WHERE id=:NEW.hotel_id; 
    END IF; 
    IF DELETING THEN 
     SELECT tenants_amount INTO amount FROM hotel WHERE id=:OLD.hotel_id; 
     UPDATE hotel SET tenants_amount=amount-1 WHERE id=:OLD.hotel_id; 
     INSERT INTO leave VALUES (SYSDATE, :OLD.hotel_id, :OLD.tourist_id); 
    END IF; 
END; 
/

마지막으로, 나는 일부 행 삽입하려고이 관계를 나타내는 테이블이기 때문에이 트리거 화재 때 DML 작업이 stay에 만들어진 :

INSERT INTO hotel VALUES (1,'Hotel 1',0); 
INSERT INTO tourist VALUES (1, 'Tourist 1'); 
INSERT INTO stay VALUES (1, 1); 

가 그리고 나는 호텔 트리거에서 오류가 : stay의 트리거가 발사 될 때이 호텔의 tenants_amount 증가하는 시도 :

ERROR at line 1: 
ORA-20001: Specified tenants amount differs from the system records 
ORA-06512: at "HOTEL_TRG", line 11 
ORA-04088: error during execution of trigger 'HOTEL_TRG' 
ORA-06512: at "STAY_TRG", line 6 
ORA-04088: error during execution of trigger 'STAY_TRG' 

이 일어나는 것이다 id=1은이 트리거가 hotel 인 트리거입니다. hotel 트리거는 tenants_amountstay의 내용과 일치하는지 확인하지만 변경 내용은 여전히 ​​표시되지 않으며 행을 찾지 못합니다. tenants_amount은 0이어야하지만 hotel의 업데이트는 1로 설정됨을 의미합니다.

이 문제를 어떻게 해결할 수 있는지 알고 싶습니다.

+0

스타일 기록해 둡니다 당신이 INSERT''에 세 개의 서로 다른 트리거를 작성해야'UPDATE'와'DELETE', 대신'IF INSERTING'과 하나 하나의 - al. 내부. – kmkaplan

+0

검색하는 동안 값을 계산할 때 성능 문제가있는 것으로 입증되지 않는 한 또는 계산할 때까지 계산할 수있는 데이터를 저장하는 것이 가장 좋습니다. 그렇게하면 트리거를 만들지 않고도 항상 * 정확한 데이터를 얻을 수 있습니다. (또는 다른 말로하면, 불일치가 발생할 수있는 기회를 소개하는 것은 계산 가능한 데이터를 저장하는 것입니다) –

답변

0

트리거 stay_trgAFTER INSERT 대신 BEFORE INSERT