[oracle] curseurs imbriqués

LCoileux -  
 dido -
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 ?




A voir également:

4 réponses

BadGuitarist Messages postés 367 Date d'inscription   Statut Membre Dernière intervention   27
 
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
LCoileux
 
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   Statut Membre Dernière intervention   27
 
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
LCoileux
 
Merci beaucoup ! Ca fonctionne parfaitement !
1
BadGuitarist Messages postés 367 Date d'inscription   Statut Membre Dernière intervention   27
 
Impecc !
A une prochaine peut-être ...

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