IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Oracle Discussion :

Annuler seulement certaines actions d'1 trigger for each row


Sujet :

Oracle

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    476
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 476
    Points : 595
    Points
    595
    Par défaut Annuler seulement certaines actions d'1 trigger for each row
    Bonjour à tous,

    Je suis pas du genre à déranger pr des questions plutot basiques mais la ca fait 3h que je cherche par tous les moyens de résoudre mon problème mais keutchi !

    Voila mon histoire :
    J'ai l'impression que lorsqu'on créait un trigger "for each row", ca sert pas à grand chose...
    Je m'explique : j'ai créé un trigger sur une table INSCRIPTION (à un module). Et lors de la modification de cette table (insertion et modification uniquement), je vérifie que le nombre d'inscrit à ce module ne dépasse pas la limite autorisée (limite donné par le champs "effecmax" de la table MODULE).
    Mais voila si j'ai opté pr l'option "for each row", c'était surtout pour faire des MAJ intelligentes mais apparament à partir du moment ou la condition 'nb d'inscrit >= effectif maximum' et que je lève un raise_application_error Oracle n'enregistre pas les mises à jour précedentes. Il annule tout...

    Quelqu'un connaitrait un moyen pour ne pas annuler les MAJ qui précédement n'ont pas levé l'exeption ?
    Ou alors une autre technique pour résoudre mon prob ?

    Au fait, rien à voir, mais je comprends rien au numéro d'erreur lorsqu'on leve "application_error". J'ai choisi -20002 parce que mon prof avait mis ca mais je peux mettre n'importe quoi ??
    Et je suis pas censé définir cette erreur quelque part ?

    Merci d'avance...

    Voia le code du trigger :
    A noter que nb_inscrit() est une fonction calculant le nombre d'inscrits
    au module à partir d'une table INSCRIPTION_BIS (table en mutation oblige)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    CREATE OR REPLACE TRIGGER CHECK_PLACE_DISPONIBLE 
    BEFORE INSERT OR UPDATE OF "CODMOD" ON "INSCRIPTION" 
    FOR EACH ROW 
     
    declare
     
    nb_max NUMBER(3);
     
     
    begin
     
     
    select effecmax into nb_max from module where codmod = :new.codmod;
     
    if (nb_max is not NULL) then 
     
     
           if (nb_inscrit(:new.codmod) >= nb_max) then
     
              raise_application_error(-20002, 'Opération impossible : les
                                      inscriptions à ce module ont atteint leur limite.');
     
     
           else
     
      	  UPDATE inscription 
                      SET  numetud = :new.numetud,  codmod = :new.codmod 
                      WHERE numetud = :old.numetud and codmod = :old.codmod;
     
     
           end if;
     
     
    end if;
     
     
    end;
    Ils flottent tous en bas

  2. #2
    Expert éminent sénior
    Avatar de SheikYerbouti
    Profil pro
    Inscrit en
    Mai 2003
    Messages
    6 760
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2003
    Messages : 6 760
    Points : 11 862
    Points
    11 862
    Par défaut
    La plage de numéros d'erreur utilisateur de l'instruction RAISE_APPLICATION_ERROR va de -20000 à -20999

    ce qui vous laisse donc 1000 erreurs et messages possibles.
    Rédacteur Oracle (Oracle ACE)
    Guide Oracle ,Guide PL/SQL, Guide Forms 9i/10g, Index de recherche
    Je ne réponds pas aux questions techniques par MP
    Blogs: Forms-PL/SQL-J2EE - Forms Java Beans

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    476
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 476
    Points : 595
    Points
    595
    Par défaut
    OK, merci de l'information
    Mais si qqn pouvait répondre à ma question sur le trigger, ca m'aiderait beaucoup
    Ils flottent tous en bas

  4. #4
    Rédacteur

    Inscrit en
    Septembre 2004
    Messages
    626
    Détails du profil
    Informations forums :
    Inscription : Septembre 2004
    Messages : 626
    Points : 848
    Points
    848
    Par défaut
    Bonjour,

    Ton pb ressemble bcp à celui-ci : http://www.developpez.net/forums/vie...02618&start=15


    Regardes mon post de 11h20.


    Quel est le code de nb_inscrit ?

    Quand tu as un trigger sur le table INSCRIPTION, ton trigger ne peut pas consulter cette même table, sinon tu auras une erreur de table mutante.


    Laly.
    In the heart of the truly greats, perfection is never achieved but endlessly pursued.

    Mon article sur les fonctions analytiques d'Oracle (calcul de moyennes mobiles, de quartiles et bien d'autres...)

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    476
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 476
    Points : 595
    Points
    595
    Par défaut
    Merci Lalystar, mais je crois que t'as mal compris mon sujet de depart.
    Je sais ce ce que c'est qu'une table mutante et par consequent lors du trigger sur la table INSCRIPTION, la requete ne se fait pas sur la TABLE INSCRIPTION mais INSCRIPTION BIS table qui évolue à chaque modifiction de la table INSCRIPTION.
    Tout cela je l'ai précisé ici :

    Voia le code du trigger :
    A noter que nb_inscrit() est une fonction calculant le nombre d'inscrits
    au module à partir d'une table INSCRIPTION_BIS (table en mutation oblige)
    Ci dessous le code de la fonction triviale "nb_inscrit'()" :

    CREATE OR REPLACE FUNCTION NB_INSCRIT (mod inscription.codmod%type) return number
    IS

    nb number(3) := 0;

    begin

    SELECT COUNT(*) INTO nb FROM inscription_bis
    WHERE codmod = mod;

    RETURN nb;

    END;
    Peut etre que j'ai pas été assez clair lors de mon 1er message alors je vais tenter de reformuler en illustrant avec un exemple.

    Le shéma des 3 tables liés au probleme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    CREATE TABLE inscription
    (
      numetud NUMBER(5), -- clé primaire
      codmod NUMBER(5),  -- clé primaire
      dateinsc DATE,
      numtd NUMBER(3)
    );
     
    CREATE TABLE inscription_bis
    (
      numetud NUMBER(5),
      codmod NUMBER(5),
    );
     
    CREATE TABLE module
    (
      codmod NUMBER(5),  -- clé primaire
      nommod VARCHAR2(30),
      effecmax NUMBER(3)
    );
    Supposons qu'il y a 2 enregistrements sur la table module.
    Pour le 1er, codmod = 1 et l'effecmax est illimité.
    Et pour le second, codmod = 2 et l'effacmax = 10.

    Sur la table INSCRIPTION, On suppose aussi qu'on a effectué des insertions : Soit 15 enregistrements au" module 1" pr 15 éléves tous différents, ce qui n'est pas un prob comme effecmax est illimité.
    C'est maintenant que je demande toute votre attention :
    Admettons que l'on à fait une erreur administrative et que l'on désire faire une UPDATE sur la valeur du codmod de la table INSCRIPTION en faisant passer codmod = 1 à codmod=2.
    En théorie, on pourrait mettre seulement 10 enregistrements à jour étant donné que le module à une capacité de 10 étudiants.
    Mais en pratique aucun étudiant n'est mis à jour à cause de cette partie du code qui en "levant application_error" annule non seulement la 11ème mise à jour (qui est impossible au vue du nombre d'effecmax) mais également les 10 premières qui elles étaient possibles.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
     if (nb_inscrit(:new.codmod) >= nb_max) then
     
              raise_application_error(-20002, 'Opération impossible : les inscriptions à ce module ont atteint leur limite.');
    Je sais pas si j'ai été clair cette fois mais j'espere que par miracle au moins un d'entre vous aurra compris mon prob ...
    et en gros je me demande si il est possible de faire une mise à jour intelligente en détournant l'exception levé par un autre moyen ou en changant carrément de technique d'approche...
    merciiiiiiiiiii !
    Ils flottent tous en bas

  6. #6
    Rédacteur

    Inscrit en
    Septembre 2004
    Messages
    626
    Détails du profil
    Informations forums :
    Inscription : Septembre 2004
    Messages : 626
    Points : 848
    Points
    848
    Par défaut
    Je crois que j'ai compris ton pb : tu fais un unique update qui fait passer du module 1 au module 2.

    Lorsque dans le trigger tu déclenches l'erreur, l'ensemble de la requête update est rollbackée. Et tu perds les 9 modifs qui auraient été autorisées.

    Il n'y a pas moyen de changer ca, c'est comme ca sous Oracle : soit une requête réussi, soit elle échoue.

    La solution consiste à faire n requêtes update.



    Laly.
    In the heart of the truly greats, perfection is never achieved but endlessly pursued.

    Mon article sur les fonctions analytiques d'Oracle (calcul de moyennes mobiles, de quartiles et bien d'autres...)

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    476
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 476
    Points : 595
    Points
    595
    Par défaut
    Oui c'est ca, t'as bien compris.
    Par contre ta réponse me desespere

    Merci...
    Ils flottent tous en bas

  8. #8
    Rédacteur

    Inscrit en
    Septembre 2004
    Messages
    626
    Détails du profil
    Informations forums :
    Inscription : Septembre 2004
    Messages : 626
    Points : 848
    Points
    848
    Par défaut
    Ce que tu cherches à faire c'est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    update   INSCRIPTION
    set      codmod = 2
    where    codmod = 1;
    Tu peux le remplacer par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    begin
       for r in (select * from INSCRIPTION where codmod = 1)
       loop
          update   INSCRIPTION b
          set      codmod = 2
          where    b.numetud = r.numedit and
                   b.codmod  = r.codmod;
       end loop;            
    end;
    A toi de gérer les erreurs éventuelles remontées par le trigger...


    Laly.
    In the heart of the truly greats, perfection is never achieved but endlessly pursued.

    Mon article sur les fonctions analytiques d'Oracle (calcul de moyennes mobiles, de quartiles et bien d'autres...)

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    476
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 476
    Points : 595
    Points
    595
    Par défaut
    merci Laly c sympa d'avoir ecrit une partie du curseur

    Mais en fait j'aurrai voulu faire fonctionner la mise à jour a partir des requetes de base UPDATE sans passer par des fonctions intermédiaires.

    En fait, C'est un petit projet qu'on a à rendre et le prof nous a pas demandé de gérer ce détail mais lors de tests ca m'énervait que ce genre de MAJ de table ne fonctionnait pas mais bon puisque c'est pas demandé explicitement, je me contenterais du maudit " constraint_error" et du roll back complet de la requete

    Voila tu sais tout, merci
    Ils flottent tous en bas

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Trigger / for each row
    Par liseprachan dans le forum Développement
    Réponses: 9
    Dernier message: 04/11/2013, 12h10
  2. [FOR EACH ROW] Comment le remplacer
    Par O Oøps O dans le forum SQL
    Réponses: 5
    Dernier message: 23/04/2009, 22h36
  3. Trigger statement ou for each row
    Par maserati dans le forum Débuter
    Réponses: 1
    Dernier message: 10/02/2009, 23h53
  4. Equivalent for each row
    Par killerti dans le forum MS SQL Server
    Réponses: 5
    Dernier message: 17/02/2008, 12h17
  5. Undo / Redo. Peut-on enregistrer que certaines actions ?
    Par Peewee dans le forum Général Java
    Réponses: 2
    Dernier message: 03/04/2006, 11h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo