2017-09-01 1 views
0

Je suis tout à fait un débutant dans PL/SQL et j'essaie de faire des contrôles assez complexes d'intégrité des données via des déclencheurs. J'ai déjà compris comment éviter les problèmes en appelant une table à l'intérieur d'un trigger qui est utilisé sur la même table (via une table externe temporaire) mais maintenant je suis confronté à un problème vraiment époustouflant: je pensais que ":NEW" faisait référence à la valeur dans mon tableau AFTER une mise à jour mais les choses ne semblent pas si simples ... C'est la nouvelle valeur SET par la mise à jour ou l'insertion ... qui semble être NULL si rien n'a été spécifié, même si le La valeur du champ correspondant est NOT NULL après la mise à jour ... ce qui me rend fou.Déclencheur PL/SQL sur INSTERT ou UPDATE: ": NEW" EST NULL => ambigu?

Mon déclencheur est défini lors de l'insertion ou la mise à jour de plusieurs variables:

CREATE OR REPLACE TRIGGER TRG_INS_UP_INSTRUMENT_EVENT 
AFTER INSERT OR UPDATE OF EVENT_ID, DATE_BEGIN,DATE_END,INSTR_ID,TYPE_EVENT_ID ON AIS_INSTRUMENT_EVENT 

Mais maintenant ... S'il y a déjà une ligne avec des champs non nuls et je fais un

UPDATE AIS_INSTRUMENT_EVENT SET INSTR_ID='642' WHERE EVENT_ID='6479' 

I en fait obtenir un ":NEW.DATE_BEGIN" qui est NULL ... pensée d'événement ni les valeurs plus anciennes ou plus récentes sont NULL (parce que je ne l'ai pas mis à jour).

Comment puis-je distinguer - dans mon déclencheur - le cas lorsque le DATE_BEGIN est mis à jour et SET volontaire NULL du cas où rien n'a été spécifié (et ce champ doit donc rester la même, mais pas nécessairement NULL ...). J'ai beaucoup de combinaison possible pour vérifier un par un ...

Merci d'avance pour votre aide!

+0

il serait utile si vous pouviez fournir un cas de test complet pour ce que vous essayez de faire (à savoir le DDL pour votre table (s) et le déclencheur, avec les données d'entrée et la sortie attendue; NB cela ne doit pas soyez vos tables exactes (par exemple nous ne nous soucions pas de ce que les colonnes/table/trigger sont appelées), mais il faut reproduire le problème que vous essayez de résoudre). Qu'est-ce qui vous fait penser que la valeur ': new' est nulle? – Boneist

Répondre

1

Ce que vous dites n'est pas vrai. : Nouvelle contient la ligne complète indépendamment du fait que la colonne est référencée dans l'instruction UPDATE:

CREATE TABLE test (test INTEGER, last_changed DATE); 

CREATE OR REPLACE TRIGGER TRG_INS_UP_TEST 
AFTER INSERT OR UPDATE OF test, last_changed ON test 
FOR EACH ROW 
BEGIN 
dbms_output.put_line('LAST CHANGED IS ' || :new.last_changed); 
END; 

INSERT INTO test (test, last_changed) VALUES (1, SYSDATE); 

COMMIT; 

UPDATE test SET test = test + 1; 

Sortie SGBD:

LAST CHANGED IS 01.09.17 

Pour obtenir ce que vous voulez que le mécanisme fonctionne légèrement différent. Vous devez regarder deux cas d'utilisation différents:

1.) Vous voulez que la gâchette ne se déclenche pas à moins qu'une certaine colonne soit mentionnée. Ce cas d'utilisation est par la référence dans la déclaration de déclenchement (INSERT OU UDATE OF "nom_colonne"). Si l'instruction INSERT/UPDATE n'affecte que les colonnes qui ne sont pas mentionnées, le déclencheur ne se déclenchera pas. 2. Vous voulez que le déclencheur ne se déclenche pas à moins qu'une certaine ligne soit modifiée. Donc, vous voulez que le déclencheur ne fonctionne que si le feu a changé. Ceci est fait par la restriction WHEN du déclencheur. Il est généralement utilisé en conjonction avec DECODE, comme ceci:

CREATE OR REPLACE TRIGGER TRG_INS_UP_TEST 
AFTER INSERT OR UPDATE OF test, last_changed ON test 
FOR EACH ROW 
WHEN (DECODE(new.test,old.test,0,1)=1 OR DECODE(new. last_changed,old. last_changed,0,1)=1) 
BEGIN 
    ... 
END; 

Pour répondre à votre question initiale: Si vous voulez la gâchette d'incendie trop que dans les cas où la DATE_BEGIN colonne est réglée pour vous NULL devez déclarer votre déclencheur en utilisant les deux approches

CREATE OR REPLACE TRIGGER TRG_INS_UP_INSTRUMENT_EVENT 
AFTER INSERT OR UPDATE OF DATE_BEGIN ON AIS_INSTRUMENT_EVENT 
FOR EACH ROW 
WHEN (DECODE(new.DATE_BEGIN,old. DATE_BEGIN,0,1)=1 AND new.DATE_BEGIN IS NULL) 

la limitation à certaines colonnes (« INSERT OU MISE a JOUR dE DATE_BEGIN ») n'est pas strictement nécessaire, mais il est bon, car il améliore les performances puisqu'elle exclut la gâchette de tir du tout.

0

Désolé je pense que j'ai fait une conclusion rapide ... Le bogue était le mien. J'ai testé sur une table "Toy" et, en effet, le: NEW n'était pas nul, même lorsqu'il n'est pas défini par la mise à jour. J'ai trouvé le bug en attendant. Tout cela est trop nouveau pour moi ;-).

Désolé pour déranger.