[oracle] curseurs imbriqués

Fermé
LCoileux - 31 mai 2010 à 21:29
 dido - 23 juin 2010 à 20:56
Bonjour,
Voila j'utilise un curseur qui va me parcourir un table de modèle de machines, et un deuxième qui doit me parcourir la liste des matricules de machine quand ceux-ci sont du modèle pointé par le curseur. En gros, je voudrais faire ceci (code pas en entier):
cursor c1 IS SELECT DISTINCT modele FROM Clients;
cursor c2 IS SELECT matricule_machine FROM Interventions WHERE modele = c1;


mais ca ne fonctionne pas, j'ai cette erreur :

LINE/COL ERROR
-------- ---------------------------------------------------
13/14    PL/SQL: SQL Statement ignored
13/88    PL/SQL: ORA-00904: "C1" : identificateur non valide


J'ai également tenté ceci :

cursor c1 IS SELECT DISTINCT modele INTO modele_en_cours FROM Clients;
cursor c2 IS SELECT matricule_machine FROM Interventions WHERE modele = modele_en_cours;


mais il ne rentre pas dans ma 2de boucle dans ce cas...

Comment faire pour que mon deuxieme courseur prenne comme condition la valeur pointée par mon premier curseur ?




4 réponses

BadGuitarist Messages postés 367 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 20 octobre 2013 27
Modifié par BadGuitarist le 1/06/2010 à 01:04
Bonsoir LCoileux,

Ton 2ième curseur ne peut utiliser la variable de type curseur (c1) mais une variable de type simple (par exemple : VARCHAR, NUMBER, ...)

En fait, ton 2ième curseur doit être un curseur paramétré :

PROCEDURE P_trtModeles IS  

    -- Sélection de tous les clients 
    CURSOR c1 IS 
      SELECT DISTINCT modele 
      FROM Clients; 

    CURSOR c2(P_modele) IS 
       SELECT matricule_machine 
         FROM Interventions 
         WHERE modele = p_modele; 

    c2_ENR  VARCHAR2(50) := NULL;  -- variable pour stocker la valeur courante 
                                                          -- de c2 

  BEGIN 
    -- parcours des clients depuis c1
    -- (déclaration implicite de c1 = écriture simplifiée) 
    FOR c1_ENR IN c1 LOOP 
       EXIT WHEN c1%NOTFOUND OR c1%NOTFOUND IS NULL;  

        -- Identification du matricule machine depuis c2 
        --   ouverture explicite du curseur c2 en passant en paramètre 
        --   le modèle courant de c1 
        OPEN c2(c1_ENR.modele);  
        FETCH c2 INTO c2_ENR; 
        IF c2%NOTFOUND THEN 
          -- Traitement si non trouvé 
          ... 
          ...
        ELSE 
          -- Traitement si trouvé 
           ...
           ...
        END IF; 
        CLOSE c2; 
        c2_ENR:= NULL;
    END LOOP; 

EXCEPTION 
  WHEN OTHERS THEN 
      IF c1%ISOPEN THEN 
        CLOSE c1; 
      END IF; 
      IF c2%ISOPEN THEN 
        CLOSE c2; 
      END IF; 

      raise_application_error(-20101, 'Erreur Identification matricule machine'); 

END P_trtModeles; 


Explications :
- Concernant le 1ier curseur : ouverture implicite du curseur (= écriture simplifiée pour ouvrir, lire et fermer un curseur) car tu dois le parcourir dans sa totalité.
- Concernant le 2ième curseur, ouverture explicite du curseur (à coder : ouverture, lecture, gestion de la variable de stockage des valeurs retournées, fermeture) car tu ne recherches qu'une partie de la sélection pointée par le curseur.

Bon courage.

Cordialement,
BG.
3
Merci de cette réponse, ça fonctionne impec ;)
J'aurais une autre question cependant, qui n'a pas de rapport avec ce problème :
est-il possible de passer en paramètre d'une procédure un mois et une année, afin que celle-ci fasse son traitement uniquement sur les lignes contenant ce mois et cette année ?

Par exemple:
create or replace procedure cout_copie_modele(date varchar2(50))
is

cout_op number;
nb_cop number;

cursor c1 is select distinct modele from Clients;

begin

--On recupere le modele de la machine
for c1_rec in c1 loop
exit when c1%NOTFOUND or c1%NOTFOUND IS NULL;
   --On poursuit le traitement seulement pour les requetes de ce mois et de cette année
.
.
.


est-ce possible ? Et si oui, comment ?

J'ai passé ma date en chaine de caractère, car débutant sous oracle, je ne sais pas si l'on peut passer uniquement le mois et l'année en temps que date...
1
BadGuitarist Messages postés 367 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 20 octobre 2013 27
Modifié par BadGuitarist le 2/06/2010 à 23:15
Bonsoir LCoileux,

Je suis ravi que tu es réussi à mettre en place la 1iere solution : bravo.

Pour le problème de paramètre de procédure, bien sûr tu peux le faire.
Si je reprends ton extrait de code, voici le comment-faire :

-- moisAnnee sera donné à l'appel de la procédure avec le même format 
--    que le paramètre de p_date de c1 (ici : MM/YYYY)
-- date_a_traiter est de type DATE et est une colonne de Clients
CREATE OR REPLACE PROCEDURE cout_copie_modele(moisAnnee IN VARCHAR2) 
IS 

  cout_op  NUMBER; 
  nb_cop   NUMBER; 

  CURSOR c1(p_date  VARCHAR2) IS 
    SELECT DISTINCT modele 
       FROM Clients 
       WHERE TO_CHAR(date_a_traiter, 'MM/YYYY')=p_date; 

BEGIN 

  -- On recupere le modele de la machine 
  FOR c1_rec IN c1(moisAnnee) LOOP 
    EXIT WHEN c1%NOTFOUND OR c1%NOTFOUND IS NULL; 

     -- Seuls les enregistrements de Clients faisant partis du mois et de l'année
     -- désignés par moisAnnee sont sélectionnés 
     . 
     . 
     . 
  END LOOP; 
END cout_copie_modele; 



L'appel de ta procédure pour traiter le mois de Mai 2010 sera le suivant :

  cout_copie_modele('05/2010'); 


A bientôt.

PS : tu peux passer en paramètre de ta procédure un type DATE ... mais il te faudra :
- gérer p_date (le paramètre de ton curseur) comme une date
- comparer la colonne date_a_traiter au début et fin du mois désigné par moisAnnee (paramètre de la procédure) ...
Ce qui est légèrement plus compliqué ;-)


Cordialement,
BG.
1
Merci beaucoup ! Ca fonctionne parfaitement !
1
BadGuitarist Messages postés 367 Date d'inscription dimanche 12 octobre 2008 Statut Membre Dernière intervention 20 octobre 2013 27
5 juin 2010 à 16:44
Impecc !
A une prochaine peut-être ...

BG
0
il est parfé vote code tres bien commenté
0