1

我在 Oracle 中有 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)
);

我有兴趣检查tenants_amount插入或更新hotel是否与表的内容一致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属性hotel。当对 DML 进行操作时触发此触发器,stay因为它是表示此关系的表

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;
/

最后,我尝试插入一些行:

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

我从酒店触发器中得到错误:

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'

这就是发生的情况:当触发 的触发器时,stay它会尝试用 增加tenants_amount酒店的id=1,这是触发 的触发器的更新hotelhotel检查的触发器是否tenants_amount与的内容一致,stay但更改仍然不可见并且它没有找到任何行。这意味着tenants_amount应该为 0,但更新时将hotel其设置为 1。

我想知道如何解决这个问题。

4

1 回答 1

0

制作触发器stay_trg AFTER INSERT而不是BEFORE INSERT

于 2017-04-23T06:55:34.150 回答