2011-09-16 3 views
0

Je reçois une curieuse erreur sur un AVANT INSERT TRIGGER, que je ne comprends pas. Même après avoir lu plusieurs questions postées ici avec des problèmes similaires.java.sql.BatchUpdateException: ORA-04091 sur INSERT AVANT TRIGGER

failed to process "method": category_id = 'foo' and request_id = '99' error: java.sql.BatchUpdateException: ORA-04091: table SCHEMA.ANIMAL_TABLE is mutating, trigger/function may not see it ORA-06512: at "SCHEMA.TRIGGER_NAME", line 7 ORA-04088: error during execution of trigger 'SCHEMA.TRIGGER_NAME'

Voici le déclencheur:

CREATE OR REPLACE TRIGGER TRIGGER_NAME 
BEFORE INSERT ON animal_table FOR EACH ROW WHEN (NEW.animal_type = 'cats') 

DECLARE base_animal_id NUMBER(19,0); base_amount NUMBER(19,0); 

BEGIN 

SELECT animal_nbr INTO base_animal_id 
FROM animal_table 
WHERE category_id = :NEW.category_id AND summary_id = :NEW.summary_id 
AND animal_type = 'special'; 

SELECT animal_amount INTO base_amount 
FROM animal_table 
WHERE category_id = :NEW.category_id AND summary_id = :NEW.summary_id 
AND animal_type = 'special'; 


IF :NEW.category_id = 'foo' THEN 

    :NEW.animal_info1 := base_animal_id; 
    :NEW.animal_info2 := base_amount; 
    :NEW.animal_info3 := '00'; 

END IF; 

END; 

Je connais les règles concernant les modifications sur la même table que le déclencheur est détenu, mais je aussi quelque chose de rouge qu'il devrait fonctionner lors du changement de nouvelles colonnes et seulement pour les: nouveaux champs. Je pensais aussi qu'il manquait peut-être le UPDATE comme événement déclencheur, mais ce n'était pas le cas. Quelqu'un peut-il m'aider s'il-vous-plaît? Comme je suis nouveau pour les déclencheurs et PL/SQL.

+0

merci, L ukas ... J'étais sur le point de faire ça. –

Répondre

0

Le message d'erreur n'a rien à voir avec la mise à jour de la table. Vous ne pouvez pas SELECT à partir de la table en cours de modification dans un déclencheur ROW niveau.

La seule solution consiste à écrire les nouvelles lignes dans une table intermédiaire dans le déclencheur de niveau de ligne. Créez ensuite un déclencheur de niveau d'instruction qui traite toutes les lignes qui ont été écrites dans la table intermédiaire (très probablement une seule instruction UPDATE avec une sous-sélection).

Vous pourriez partir sans le niveau de déclenchement de la ligne et la table intermédiaire si vous pouvez identifier les lignes à post-traitées à l'intérieur du niveau de déclenchement de l'instruction par exemple en vérifiant animal_type = 'chats' et category_id = 'foo'.

Si tel est le cas, le déclencheur suivant (non testé !!!) pourrait faire ce que vous voulez (au lieu de celui que vous avez)

CREATE OR REPLACE TRIGGER TRIGGER_NAME 
AFTER INSERT ON animal_table 
BEGIN 

    UPDATE animal_table 
    SET (animal_info1, 
      animal_info2, 
      animal_info3) = (SELECT animal_nbr, animal_amount, '00' 
          FROM animal_table t2 
          WHERE t2.category_id = animal_table.category_id 
          AND t2.sumary_id = animal_table.summary_id 
          AND t2.animal_type = 'special' 
         ) 
    WHERE animal_type = 'cats' 
    AND category_id = 'foo' 

END; 

Une autre chose PL/SQL plus générale: Vous n » pas besoin d'exécuter un SELECT pour chaque colonne que vous souhaitez récupérer, vous pouvez le faire dans une instruction select unique si les conditions sont les mêmes:

SELECT animal_nbr, animal_amount 
    INTO base_animal_id, base_amount 
FROM animal_table 
WHERE category_id = :NEW.category_id 
    AND summary_id = :NEW.summary_id 
    AND animal_type = 'special'; 

(Notez les deux colonnes dans la sélection et dans la liste)

+0

Belle réponse ... Un ajout que j'ai ajouté. –

Questions connexes