J'ai 4 tables dans Oracle: hotel
, tourist
, stay
, leave
. Le tableau stay
fait référence à un touriste séjournant dans un hôtel, et la table leave
stocke les informations de la date à laquelle un touriste quitte un hôtel.Les déclenchements simultanés rendent difficiles les insertions et les mises à jour
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)
);
Je suis intéressé par vérifier si tenants_amount
d'un insert ou mise à jour sur hotel
est compatible avec le contenu de la table stay
, donc j'écrit ce déclencheur pour 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;
/
J'ai aussi écrit un deuxième déclencheur pour stocker les informations de leave
et la gestion de l'attribut tenants_amount
de hotel
. Ce feu de déclenchement lorsque les opérations DML sont faites sur stay
parce qu'il est le tableau qui représente cette relation
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;
/
Enfin, j'essaie d'insérer quelques lignes:
INSERT INTO hotel VALUES (1,'Hotel 1',0);
INSERT INTO tourist VALUES (1, 'Tourist 1');
INSERT INTO stay VALUES (1, 1);
Et je reçois l'erreur de la détente de l'hôtel :
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'
C'est ce qui se passe: lorsque le déclencheur de stay
est tiré, il tente d'augmenter le tenants_amount
de l'hôtel avec id=1
, il s'agit d'une mise à jour qui déclenche le déclenchement de hotel
. Le déclencheur de hotel
vérifie si le tenants_amount
est cohérent avec le contenu de stay
mais les modifications ne sont toujours pas visibles et il ne trouve aucune ligne. Cela signifie que le tenants_amount
devrait être 0 mais la mise à jour sur hotel
l'a mis à 1.
Je veux savoir comment puis-je résoudre ce problème.
note Style: vous devez écrire trois déclencheur distinct, sur 'INSERT',' update' et 'delete', au lieu d'un seul avec un' IF INSERTING' - Al. à l'intérieur. – kmkaplan
Il est généralement préférable de ne pas * stocker * les données pouvant être * calculées *, à moins qu'il ne soit démontré que le calcul de la valeur lors de la récupération pose un problème de performances. De cette façon, vous vous assurez que les données sont * toujours * précises sans avoir à créer de déclencheurs. (Ou, pour le dire autrement, c'est le * stockage * des données calculables qui * introduit * la possibilité que l'incohérence apparaisse) –