2010-08-31 6 views
1

le problème est le suivant: J'ai implémenté un trigger sur la table appelée CLAN_AFFILIATI qui augmente (si inseriemento) et diminue (en cas d'annulation) un attribut (NUMAFFILIATI) d'une autre table appelée CLAN. ce que je ferais est de bloquer la NUMAFFILIATI mise à jour du Clan par l'utilisateur et avait pensé à r autre Trigge sur CLAN qui a fait ceci:problème avec déclencheur dans oracle

déclencheur sur CLAN_AFFILIATI (CLAN VARCHAR, affiliato VARCHAR, Ruolo VARCHAR)

CREATE OR REPLACE TRIGGER "AggiornamentoNumAffiliati" 
AFTER INSERT OR DELETE ON CLAN_AFFILIATI 
FOR EACH ROW 
DECLARE 
    CLAN_APPARTENENZA VARCHAR(20); 
BEGIN 


    IF INSERTING THEN 

    SELECT NOME INTO CLAN_APPARTENENZA 
    FROM CLAN 
    WHERE NOME=:new.CLAN; 

    UPDATE CLAN 
    SET NUMAFFILIATI=NUMAFFILIATI+1 
    WHERE CLAN_APPARTENENZA=NOME; 
    ELSE 
    SELECT NOME INTO CLAN_APPARTENENZA 
    FROM CLAN 
    WHERE NOME=:old.CLAN; 

    UPDATE CLAN 
    SET NUMAFFILIATI=NUMAFFILIATI-1 
    WHERE CLAN_APPARTENENZA=NOME; 
    END IF; 
END; 

déclencheur sur CLAN (NOM VARCHAR, NUMAFFILIATI ENTIER)

CREATE OR REPLACE TRIGGER "ModificaNumAffiliati" 
BEFORE INSERT OR UPDATE OF NUMAFFILIATI ON CLAN 
FOR EACH ROW 
DECLARE 
CONT NUMBER:=0; 
BEGIN 

    IF INSERTING THEN 
     IF :new.NUMAFFILIATI <> 0 THEN 
      RAISE_APPLICATION_ERROR(-20016,'NUMERO ERRATO'); 
     END IF; 
    ELSE 
     SELECT COUNT(*) INTO CONT 
     FROM CLAN_AFFILIATI 
     WHERE :old.NOME=CLAN; 
     IF CONT <> :new.NUMAFFILIATI THEN 
      RAISE_APPLICATION_ERROR(-20017,'NUMERO ERRATO'); 
     END IF; 
    END IF; 
END; 

mais alors je fais signale une erreur:

error ORA-04091: Table ANTONIO.CLAN_AFFILIATI is being modified, the trigger/function can not read 
ORA-06512: at "ANTONIO.ModificaNumAffiliati", line 10 
ORA-04088: error during execution of trigger 'ANTONIO.ModificaNumAffiliati' 
ORA-06512: at "ANTONIO.AggiornamentoNumAffiliati", line 12 
ORA-04088: error during execution of trigger 'ANTONIO.AggiornamentoNumAffiliati 

comment puis-je résoudre ce problème ....

+0

Pourriez-vous fournir le code d'erreur Oracle exact? –

+0

erreur ORA-04091: Le tableau ANTONIO.CLAN_AFFILIATI est en cours de modification, le déclencheur/la fonction ne peut pas lire ORA-06512: à "ANTONIO.ModificaNumAffiliati", ligne 10 ORA-04088: erreur lors de l'exécution du déclencheur 'ANTONIO.ModificaNumAffiliati' ORA- 06512: à "ANTONIO.AggiornamentoNumAffiliati", ligne 12 ORA-04088: erreur lors de l'exécution du déclencheur 'ANTONIO.AggiornamentoNumAffiliati – kafka

Répondre

2

Cette solution est propably:

Je l'ai testé avec ces tables exemple:

CREATE TABLE CLAN_AFFILIATI(CLAN VARCHAR2(100),AFFILIATO VARCHAR2(100),RUOLO VARCHAR2(100)); 
CREATE TABLE CLAN (NOME VARCHAR2(100) ,NUMAFFILIATI NUMBER(10)); 

Vous avez besoin ce paquet d'aide.

CREATE OR REPLACE PACKAGE STORE_NOMES 
AS 

    TYPE record_nomes IS RECORD (
     nome VARCHAR2(100), 
     operation VARCHAR2(100) -- insert or delete 
    ); 

    TYPE array_type_nomes IS TABLE OF record_nomes INDEX BY BINARY_INTEGER; 
    g_array_nomes array_type_nomes; 

END STORE_NOMES; 
/

Trigger sur la table CLAN:

CREATE OR REPLACE TRIGGER MODIFICANUMAFFILIATI 
    BEFORE INSERT OR UPDATE OF NUMAFFILIATI ON CLAN 
FOR EACH ROW 
DECLARE 
    l_CONT NUMBER:=0; 
BEGIN 

    IF INSERTING THEN 
     -- prevent inserting <> 0 
     IF :new.NUMAFFILIATI <> 0 THEN 
      RAISE_APPLICATION_ERROR(-20016,'NUMERO ERRATO'); 
     END IF; 
    ELSE 
     SELECT COUNT(*) INTO l_CONT 
     FROM CLAN_AFFILIATI 
     WHERE CLAN = :old.NOME; 
     IF l_CONT <> :new.NUMAFFILIATI THEN 
      RAISE_APPLICATION_ERROR(-20017,'NUMERO ERRATO'); 
     END IF; 
    END IF; 
END; 
/

Avant déclenchement de l'instruction sur la table CLAN_AFFILIATI:

CREATE OR REPLACE TRIGGER TRG_CLAN_AFFILIATI_BEFORE_STMT 
    BEFORE INSERT OR DELETE 
ON CLAN_AFFILIATI 
DECLARE 
BEGIN 
    STORE_NOMES.g_array_nomes.DELETE; 
END; 
/

Après déclenchement de l'instruction sur la table CLAN_AFFILIATI:

CREATE OR REPLACE TRIGGER TRG_CLAN_AFFILIATI_AFTER_STMT 
    AFTER INSERT OR DELETE 
ON CLAN_AFFILIATI 
DECLARE 
BEGIN 
    FOR i IN STORE_NOMES.g_array_nomes.FIRST..STORE_NOMES.g_array_nomes.LAST LOOP 
     IF(STORE_NOMES.g_array_nomes(i).operation = 'INSERTING') THEN 
      UPDATE CLAN 
      SET NUMAFFILIATI=NUMAFFILIATI+1 
      WHERE NOME = STORE_NOMES.g_array_nomes(i).NOME; 
     ELSIF(STORE_NOMES.g_array_nomes(i).operation = 'DELETING') THEN 
      UPDATE CLAN 
      SET NUMAFFILIATI=NUMAFFILIATI-1 
      WHERE NOME = STORE_NOMES.g_array_nomes(i).NOME; 
     END IF; 
    END LOOP; 
END; 
/

Insérer une ligne/Dele te trigger sur la table CLAN_AFFILIATI:

CREATE OR REPLACE TRIGGER AGGIORNAMENTONUMAFFILIATI 
    BEFORE INSERT OR DELETE ON CLAN_AFFILIATI 
FOR EACH ROW 
DECLARE 
    l_CLAN_APPARTENENZA VARCHAR(20); 
BEGIN 

    IF INSERTING THEN 

    SELECT NOME INTO l_CLAN_APPARTENENZA 
    FROM CLAN 
    WHERE NOME = :new.CLAN; 

    STORE_NOMES.g_array_nomes(STORE_NOMES.g_array_nomes.COUNT).nome := :new.CLAN; 
    STORE_NOMES.g_array_nomes(STORE_NOMES.g_array_nomes.LAST).operation := 'INSERTING'; 

    ELSE 
    SELECT NOME INTO l_CLAN_APPARTENENZA 
    FROM CLAN 
    WHERE NOME = :old.CLAN; 

    STORE_NOMES.g_array_nomes(STORE_NOMES.g_array_nomes.COUNT).nome := :old.CLAN; 
    STORE_NOMES.g_array_nomes(STORE_NOMES.g_array_nomes.LAST).operation := 'DELETING'; 
    END IF; 
END; 
/

travaille maintenant ce (sans ORACLE-EXCEPTION):

INSERT INTO CLAN(NOME, NUMAFFILIATI) VALUES('Antonio', 0); 
INSERT INTO CLAN_AFFILIATI(CLAN,AFFILIATO,RUOLO) values('Antonio','Affiliato1','Ruolo1'); 
INSERT INTO CLAN_AFFILIATI(CLAN,AFFILIATO,RUOLO) values('Antonio','Affiliato2','Ruolo2'); 
+0

merci pour votre réponse vous avez été très gentil, presque tout fonctionne parfaitement, le seul problème est l'annulation, à savoir NUMAFFILIATI n'est pas mis à jour si une ligne est supprimée de CLAN_AFFILIATI – kafka

+0

FIRST - est déclencheur déclenché "TRG_CLAN_AFFILIATI_BEFORE_STMT" - Oracle le soulève avant toute manipulation de données dans la table. C'est l'endroit où vous devez effacer array (STORE_NOMES.g_array_nomes) - sinon cela ne fonctionnera pas. DEUXIÈMEMENT - est déclenché Trigger "AGGIORNAMENTONUMAFFILIATI", il y a un endroit, où stocké NOMES dans le tableau (STORE_NOMES.g_array_nomes) et ses opérations (INSERT ou DELETE). TROISIEME (et dernier) est déclenché après le déclencheur d'instruction "TRG_CLAN_AFFILIATI_AFTER_STMT", Oracle qui a augmenté après que tout DML (data-manupilation) soit fait. C'est l'endroit où vous pouvez appeler la mise à jour sur la table CLAN. –

+0

Oracle TYPE STORE_NOMES.g_array_nomes est similaire à MEMORY (se souvient des noms et des opérations effectuées). –

0

Modifier le premier déclencheur « AggiornamentoNumAffiliati » afin qu'il ne cherche pas à mettre à jour immédiatement clan, mais stocke le nom (NOME) dans un PL/SQL-Table dans un paquet; Ensuite, vous créez un déclencheur AFTER INSERT ou DELETE (mais sans clause FOR EACH ROW) qui lit la table PL/SQL du package et met à jour les CLAN en conséquence.

+0

comment créer une table PL/SQL? – kafka

+0

voir la réponse de martin, il était plus diligent que moi –

0

Je n'ai pas mes outils de développement avec moi, mais il me semble que vous vous mettez dans une sorte de dépendance cyclique. Lorsque votre déclencheur CLAN_AFFILIATI est déclenché, vous effectuez une mise à jour de CLAN qui appelle le second déclencheur, qui a une sélection de la table CLAN_AFFILIATI dans le bloc ELSE.

Peut-être qu'avant insertion (première requête), et après insertion (deuxième requête) ont également un effet.

0

ORA-04091 est également connu comme une "table muter" erreur - essentiellement, les déclencheurs de ligne ne peut pas interroger ou modifiez la table sur laquelle la gâchette [email protected] La réponse de Martin est la description classique de la façon de contourner ce problème, mais si vous êtes sur Oracle 11+, vous pouvez utiliser un compound trigger pour faire la même chose.

Partagez et appréciez.

Questions connexes