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

PL/SQL Oracle Discussion :

Création d'une fonction


Sujet :

PL/SQL Oracle

  1. #1
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 36
    Par défaut Création d'une fonction
    Bonjour à tous

    Tout d'abord, je vous souhaite un très joyeux noël ainsi que de bonnes fêtes

    Noël c'est le temps des chocolats, du foie gras, des bûches... et du travail pour beaucoup d'étudiants ! :p

    Si j'en viens à poster ici c'est que je n'arrive vraiment pas à trouver mes erreurs. Au bout de deux jours de recherches je dois accélérer les choses en raison des nombreux projets et des révisions qui s'annoncent pour ces partiels de début d'année.

    J'aimerais donc solliciter votre aide.

    Dans le cadre d'un projet j'utilise une base oracle (Express edition 10g) en localhost. Je travaille donc sur la plateforme d'administration classique.

    Lors de la création d'une fonction, j'ai très régulièrement ce message d'erreur:

    Not found

    The requested URL /apex/wwv_flow.show was not found on this server
    Malgré mes recherches, je n'en trouve pas la cause.
    J'ai pensé que c'était du à une mauvaise utilisation d'un tableau, à l'appel d'une fonction (Que j'ai du coup temporairement supprimé), ou encore à la syntaxe de mes structures conditionnelles mais à chaque fois, je pense toucher le but sans toutefois l'atteindre.

    J'ai tant bien que mal essayé de déboguer mon code mais je n'ai rien trouvé. Lorsque je n'ai pas ce fameux message, il m'arrive d'avoir "SQL Statement running", sans que cela ne s'arrête. C'est étrange. J'aurais pensé à une boucle infinie, mais je n'ai rien trouvé dans ce sens, d'ailleurs cela m'étonnerait qu'à la compilation, la fonction soit exécutée d'autant plus qu'elle pourrait nécessiter des paramètres.

    Ma fonction permet de savoir si un étudiant a terminé tous les devoirs de la semaine ou non (Il s'agit de la modélisation d'un cartable électronique ).
    Voici le code:

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    CREATE OR REPLACE FUNCTION statutDevoirsSemaine RETURN NUMBER AS
     
    --Variables relatives à la date du jour.
    nomDuJour varchar2(10);
    numDuJour varchar2(2);
    numMois varchar2(2);
    annee varchar2(4);
     
    bissextile number(1,0):=0; --Valeurs: 0 si l'année n'est pas bissextile, 1 sinon.
    numMaxMois type_tab; --Tableau regroupant les numéros maximaux des jours de chaque mois
    termine NUMBER(1,0):=1; --Variable retournée: 1 si tous les devoirs de la semaine sont terminés, 0 sinon.
    cpt NUMBER(1,0):=0; --Compteur de boucle
    jourParcouru varchar2(2); --Numéro du jour parcouru pour la vérification des statuts des devoirs
    nbJoursVerifies NUMBER(5); --Nombre de jours à vérifier (Dépend de la date du jour)
     
    BEGIN
    --On enregistre le nom du jour
    nomDuJour:=to_char(sysdate, 'day');
    --Suppression des espaces (Voir explications dans le rapport)
    nomDuJour:=TRANSLATE(nomDuJour, '1 ','1');
     
    --On enregistre le numéro du jour
    numDuJour:=to_char(sysdate, 'DD');
     
    --Puis le numéro du mois
    numMois:=to_char(sysdate, 'MM');
     
    --On cherche à savoir si l'on est dans une année bissextile ou non.
    --Algorithme expliqué dans le rapport.
    annee:=to_char(sysdate, 'YYYY');
    IF mod(annee,4)= 0 THEN
      bissextile:=1;
      IF mod(annee,100) = 0 THEN
        bissextile:=0;
        IF mod(annee,400) = 0 THEN
          bissextile:=1;
        END IF;
      END IF;
    END IF;
     
    --Selon que l'année soit bissextile ou non, on enregistre dans un tableau le numéro maximal du jour. NOTE; C'est ici que je voulais faire appel à une fonction de remplissage.
    IF bissextile = 0 THEN --Si l'année n'est pas bissextile
      numMaxMois:= type_tab('31','28','31','30','31','30','31','31','30','31','30','31');
    ELSE --Si l'année est bissextile
      numMaxMois:= type_tab('31','29','31','30','31','30','31','31','30','31','30','31'); 
    END IF;
     
     
    IF nomDuJour='monday' THEN 
      --On doit vérifier les devoirs pour les 5 prochains jours (Mardi, Mercredi, Jeudi, Vendredi, Samedi)
      nbJoursVerifies:=5;
    ELSIF nomDuJour='tuesday' THEN
      --On doit vérifier les devoirs pour les 4 prochains jours (Mercredi, Jeudi, Vendredi, Samedi)
      nbJoursVerifies:=4;
    ELSIF nomDuJour='wednesday' THEN
      --On doit vérifier les devoirs pour les 3 prochains jours (Jeudi, Vendredi, Samedi)
      nbJoursVerifies:=3;
    ELSIF nomDuJour='thursday' THEN
      --On doit vérifier les devoirs pour les 2 prochains jours (Vendredi, Samedi)
      nbJoursVerifies:=2;
    ELSIF nomDuJour='friday' THEN
      --On doit vérifier les devoirs pour le lendemain (Samedi)
      nbJoursVerifies:=1;
    ELSIF nomDuJour='saturday' THEN
      --On doit vérifier les devoirs pour la semaine suivante
      nbJoursVerifies:=6;
      numDuJour:=numDuJour+1; --On fait comme si on était dimanche [A modifier, partiellement incorrect]
    ELSE
     --On est dimanche, on doit vérifier les devoirs pour la semaine suivante.
     nbJoursVerifies:=6;
    END IF;
     
    WHILE (termine = 1 AND cpt < nbJoursVerifies) LOOP
    IF numDuJour + (cpt+1) <= numMaxMois(numMois) THEN
     jourParcouru:=numDuJour + (cpt+1) || numMois || annee;
    ELSE
     jourParcouru:=(cpt+1);
    END IF;
    termine:=statutDevoirs(jourParcouru); --Appel à la fonction unitaire
    cpt:=cpt+1;
    END LOOP;
     
    RETURN termine;
    END;
    En espérant que vous pourrez me guider, je vous remercie d'avance.

    ps : déclaration de type_tab:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CREATE OR REPLACE TYPE  "TYPE_TAB" IS VARRAY(12) OF VARCHAR2(2);

  2. #2
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Attention à tes déclarations et tes calculs sur les varchar2
    exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    annee varchar2(4);
    annee:=to_char(sysdate, 'YYYY');
    IF mod(annee,4)= 0
    Ca ne va pas générer d'erreur, certes, mais il est préférable de déclarer un number
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    annee NUMBER;
    annee:= TO_NUMBER(to_char(sysdate, 'YYYY')); 
    ou mieux : annee:= EXTRACT(YEAR FROM sysdate); 
    IF mod(annee,4)= 0
    Ensuite jour parcouru, là c'est faux
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    jourParcouru varchar2(2);
    jourParcouru:=numDuJour + (cpt+1) || numMois || annee;
    vu comme ça je ne saurais même pas te dire ce que vaut jourParcouru !
    Concatener des chaines de caractères avec des sommes de varchar...

    Enfin, je n'ai pas compris l'algo, à quoi sert le tableau ? Tu ne peux pas passer par la fonction Next_Day et tout gérer en date réelle ?

  3. #3
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 36
    Par défaut
    En effet, j'ai laissé passer une grosse erreur sur les types !

    En fait, j'avais tout testé avec des DBMS_OUTPUT et j'avais les résultats escomptés donc je ne me suis pas plus inquiété que cela.

    Concernant jourParcouru, il s'agit d'obtenir une chaîne du type "JJMMAAAA".

    numDuJour + (cpt+1) => le pl/sql semble permissif sur les opérateurs, il semblerait que cela fonctionne et on obtient donc un numéro à deux chiffres.

    Par contre, une erreur bête dans la déclaration de jourParcouru; il lui faut 8 caractères donc varchar2(8).


    En fait le tableau sert lorsque l'on change de jour. Exemple, on est le 31 décembre, on passe au jour suivant mais avant de faire un "+1" on vérifie que l'on n'est pas déjà au dernier jours du mois ce qui est le cas ici. Cela permet de passer au 1 et non au 32.

    J'ai corrigé d'autres erreurs.

    Je n'avais pas connaissance de cette fonction Next_Day.

    Pour moi, c'est plus facile de gérer des dates avec le format "JJMMAAAA" dans ma base de données, surtout pour le côté java.

    Mais malgré ces corrections, cela ne marche toujours pas. J'ai "SQL statement running" sans arrêt.

    Le nouveau code :
    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    CREATE OR REPLACE FUNCTION statutDevoirsSemaine RETURN NUMBER AS
     
    --Variables relatives à la date du jour.
    nomDuJour varchar2(10);
    numDuJour varchar2(2);
    numMois varchar2(2);
    annee NUMBER;
     
    bissextile number(1,0):=0; --Valeurs: 0 si l'année n'est pas bissextile, 1 sinon.
    numMaxMois type_tab; --Tableau regroupant les numéros maximaux des jours de chaque mois
    termine NUMBER(1,0):=1; --Variable retournée: 1 si tous les devoirs de la semaine sont terminés, 0 sinon.
    cpt NUMBER(1,0):=0; --Compteur de boucle
    jourParcouru varchar2(10); --Numéro du jour parcouru pour la vérification des statuts des devoirs
    nbJoursVerifies NUMBER(5); --Nombre de jours à vérifier (Dépend de la date du jour)
     
    BEGIN
    --On enregistre le nom du jour
    nomDuJour:=to_char(sysdate, 'day');
    --Suppression des espaces (Voir explications dans le rapport)
    nomDuJour:=TRANSLATE(nomDuJour, '1 ','1');
     
    --On enregistre le numéro du jour
    numDuJour:=to_char(sysdate, 'DD');
     
    --Puis le numéro du mois
    numMois:=to_char(sysdate, 'MM');
     
    --On cherche à savoir si l'on est dans une année bissextile ou non.
    --Algorithme expliqué dans le rapport.
    annee:=EXTRACT(YEAR FROM sysdate); 
    IF mod(annee,4)= 0 THEN
      bissextile:=1;
      IF mod(annee,100) = 0 THEN
        bissextile:=0;
        IF mod(annee,400) = 0 THEN
          bissextile:=1;
        END IF;
      END IF;
    END IF;
     
    --Selon que l'année soit bissextile ou non, on enregistre dans un tableau le numéro maximal du jour. NOTE; C'est ici que je voulais faire appel à une fonction de remplissage.
    IF bissextile = 0 THEN --Si l'année n'est pas bissextile
      numMaxMois:= type_tab('31','28','31','30','31','30','31','31','30','31','30','31');
    ELSE --Si l'année est bissextile
      numMaxMois:= type_tab('31','29','31','30','31','30','31','31','30','31','30','31'); 
    END IF;
     
     
    IF nomDuJour='monday' THEN 
      --On doit vérifier les devoirs pour les 5 prochains jours (Mardi, Mercredi, Jeudi, Vendredi, Samedi)
      nbJoursVerifies:=5;
    ELSIF nomDuJour='tuesday' THEN
      --On doit vérifier les devoirs pour les 4 prochains jours (Mercredi, Jeudi, Vendredi, Samedi)
      nbJoursVerifies:=4;
    ELSIF nomDuJour='wednesday' THEN
      --On doit vérifier les devoirs pour les 3 prochains jours (Jeudi, Vendredi, Samedi)
      nbJoursVerifies:=3;
    ELSIF nomDuJour='thursday' THEN
      --On doit vérifier les devoirs pour les 2 prochains jours (Vendredi, Samedi)
      nbJoursVerifies:=2;
    ELSIF nomDuJour='friday' THEN
      --On doit vérifier les devoirs pour le lendemain (Samedi)
      nbJoursVerifies:=1;
    ELSIF nomDuJour='saturday' THEN
      --On doit vérifier les devoirs pour la semaine suivante
      nbJoursVerifies:=6;
      numDuJour:=numDuJour+TO_CHAR(1); --On fait comme si on était dimanche [A modifier, partiellement incorrect]
    ELSE
     --On est dimanche, on doit vérifier les devoirs pour la semaine suivante.
     nbJoursVerifies:=6;
    END IF;
     
    WHILE (termine = 1 AND cpt < nbJoursVerifies) LOOP
    IF TO_NUMBER(numDuJour) + (cpt+1) < TO_NUMBER(numMaxMois(numMois)) THEN
     jourParcouru:= TO_CHAR(TO_NUMBER(numDuJour) + (cpt+1));
     jourParcouru:= jourParcouru || numMois || TO_CHAR(annee);
    ELSE
     jourParcouru:= TO_CHAR(cpt+1) || TO_CHAR(TO_NUMBER(numMois)+1) || TO_CHAR(annee);
    END IF;
    termine:=statutDevoirs(jourParcouru); --Appel à la fonction unitaire
    cpt:=cpt+1;
    END LOOP;
     
    RETURN termine;
    END;
    Pour info: code de la fonction unitaire (qui compile parfaitement):

    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
    39
    --Fonction qui permet de savoir si les devoirs pour la date précisée en paramètre ont été effectués.
    --Le format de la date doit respecter la syntaxe JJMMAAAA. Une exception sera levée dans le cas contraire.
    --Valeurs de retour: 0 si les devoirs ne sont pas terminés, 1 sinon.
     
    CREATE OR REPLACE FUNCTION statutDevoirs(dateChoisie varchar2) RETURN NUMBER AS
     
    valretour NUMBER:=1; --valeur retournée
    exceptionDate EXCEPTION;
    Cursor devoirsLendemain IS
      SELECT statutDevoir
      FROM DEVOIR
      WHERE dateDevoir = dateChoisie;
    statutDevoirCourant Devoir.statutDevoir%TYPE;
     
    BEGIN
      --On vérifie que la date respecte le bon format (utilisation d'une expression régulière)
      IF REGEXP_LIKE (dateChoisie, '[01-31][01-12]2[0-9][1-9][0-9]') THEN
     
        --On part du principe que les devoirs sont terminés.
        --Dès que l'on rencontre un devoir non terminé, on retourne 0.
        OPEN devoirsLendemain;
        LOOP
          FETCH devoirsLendemain INTO statutDevoirCourant;
          EXIT WHEN devoirsLendemain%NOTFOUND;
          IF valretour = 1 AND statutDevoirCourant = 0 THEN
            valretour:=0;
          END IF;
        END LOOP;
        CLOSE devoirsLendemain;
      ELSE 
        RAISE exceptionDate;
      END IF;
     
    EXCEPTION
      WHEN exceptionDate THEN
        DBMS_OUTPUT.PUT_LINE('Erreur, la date indiquée est incorrecte.');
     
    RETURN valretour;
    END;

    J'ai commencé à réécrire la fonction en changant d'algo comme tu le proposes; mais c'est à ne rien comprendre, pour le même code j'ai réussi à le compiler une fois, une autre fois je vais avoir un "SQL Statement running", et une autre fois un "Apex/..... not found". Je fais des drop function pour éviter le replace mais cela ne change pas grand chose..

    Code, pas très avancé mais dès ce stade cela compile mal:
    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
    39
    40
    41
    42
    43
    44
    45
    46
    DROP FUNCTION statutDevoirsSemaine;
     
    CREATE FUNCTION statutDevoirsSemaine RETURN NUMBER AS
     
    --Variables relatives à la date du jour.
    nomDuJour varchar2(10);
    annee NUMBER:= EXTRACT(YEAR FROM sysdate); 
     
    termine NUMBER(1,0):=1; --Variable retournée: 1 si tous les devoirs de la semaine sont terminés, 0 sinon.
    cpt NUMBER(1,0):=0; --Compteur de boucle
    jourParcouru varchar2(10); --Numéro du jour parcouru pour la vérification des statuts des devoirs
    nbJoursVerifies NUMBER(5):=0; --Nombre de jours à vérifier (Dépend de la date du jour)
     
    BEGIN
    --On enregistre le nom du jour
    nomDuJour:=to_char(sysdate, 'day');
    --Suppression des espaces (Voir explications dans le rapport)
    nomDuJour:=TRANSLATE(nomDuJour, '1 ','1');
    nomDuJour:=upper(nomDuJour);
     
    IF nomDuJour='MONDAY' THEN 
      --On doit vérifier les devoirs pour les 5 prochains jours (Mardi, Mercredi, Jeudi, Vendredi, Samedi)
      nbJoursVerifies:=5;
    ELSIF nomDuJour='TUESDAY' THEN
      --On doit vérifier les devoirs pour les 4 prochains jours (Mercredi, Jeudi, Vendredi, Samedi)
      nbJoursVerifies:=4;
    ELSIF nomDuJour='WEDNESDAY' THEN
      --On doit vérifier les devoirs pour les 3 prochains jours (Jeudi, Vendredi, Samedi)
      nbJoursVerifies:=3;
    ELSIF nomDuJour='THURSDAY' THEN
      --On doit vérifier les devoirs pour les 2 prochains jours (Vendredi, Samedi)
      nbJoursVerifies:=2;
    ELSIF nomDuJour='FRIDAY' THEN
      --On doit vérifier les devoirs pour le lendemain (Samedi)
      nbJoursVerifies:=1;
    ELSIF nomDuJour='SATURDAY' THEN
      --On doit vérifier les devoirs pour la semaine suivante
      nbJoursVerifies:=6;
      nomDuJour:='SUNDAY';
    ELSE
     --On est dimanche, on doit vérifier les devoirs pour la semaine suivante.
     nbJoursVerifies:=6;
    END IF;
     
    RETURN termine;
    END;

  4. #4
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Ta fonction statutDevoirs ne fonctionne pas vraiment et est perfectible.
    1 - Pas de return quand ça marche !
    2 - Evite les Open cursor, c'est chiant, faut gérer les close, les affectations, etc... préfère les FOR LOOP beaucoup plus pratique.
    3 - Opti : imaginons que tu aies 5 Millions de devoir le même jour.. tu vas boucler 5 M de fois, même si la première ligne ramenée a un statut 0 ? Mieux vaut privilégier les traitements sur la base qu'en PL
    Il te suffit de noter les cas :
    Ta fonction renvoie 1 par défaut
    Ta fonction renvoie 0 si au moins un devoir a un statut 0

    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
    --Fonction qui permet de savoir si les devoirs pour la date précisée en paramètre ont été effectués.
    --Le format de la date doit respecter la syntaxe JJMMAAAA. Une exception sera levée dans le cas contraire.
    --Valeurs de retour: 0 si les devoirs ne sont pas terminés, 1 sinon.
     
    CREATE OR REPLACE FUNCTION statutDevoirs(dateChoisie varchar2) RETURN NUMBER AS
     
      valretour NUMBER:=1; --valeur retournée
      exceptionDate EXCEPTION;
     
    BEGIN
      --On vérifie que la date respecte le bon format (utilisation d'une expression régulière)
      IF REGEXP_LIKE (dateChoisie, '[01-31][01-12]2[0-9][1-9][0-9]')
      THEN
     
    		--On part du principe que les devoirs sont terminés.
        --Dès que l'on rencontre un devoir non terminé, on retourne 0.
        BEGIN
        	SELECT 0
          INTO valretour
          FROM DEVOIR
      	WHERE dateDevoir = dateChoisie
       	AND statutDevoir = 0
          AND ROWNUM = 1;
        EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
        END:
     
      ELSE 
        RAISE exceptionDate;
      END IF;
     
    	RETURN valretour; 
     
    EXCEPTION
    WHEN exceptionDate THEN
        DBMS_OUTPUT.PUT_LINE('Erreur, la date indiquée est incorrecte.');
    		RETURN valretour;
    END;

  5. #5
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 36
    Par défaut
    Merci pour ton implication,

    Je ne savais pas que l'on ne sortait pas du bloc d'exception !

    Pour la boucle, oui c'est exactement ce que je voulais faire (à l'image de la boucle dans la fonction pour la semaine) j'ai juste oublié la condition ultime...

    Un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    EXIT WHEN devoirsLendemain%NOTFOUND OR valretour = 0;
    devrait suffire non ? Ton astuce est assez.. astucieuse il faudrait étudier la complexité pour savoir quelle méthode serait la plus avantageuse. Au fond, la requête est la même.

    Concernant les curseurs, j'aime bien cette méthode :p Ceci dit, les deux fonctionnent je ne pense pas avoir fait d'erreur de ce côté là.

    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
    CREATE OR REPLACE FUNCTION statutDevoirs(dateChoisie varchar2) RETURN NUMBER AS
     
    valretour NUMBER:=1; --valeur retournée
    exceptionDate EXCEPTION;
    Cursor devoirsLendemain IS
      SELECT statutDevoir
      FROM DEVOIR
      WHERE dateDevoir = dateChoisie;
    statutDevoirCourant Devoir.statutDevoir%TYPE;
     
    BEGIN
      --On vérifie que la date respecte le bon format (utilisation d'une expression régulière)
      IF REGEXP_LIKE (dateChoisie, '[01-31][01-12]2[0-9][1-9][0-9]') THEN
     
        --On part du principe que les devoirs sont terminés.
        --Dès que l'on rencontre un devoir non terminé, on retourne 0.
        OPEN devoirsLendemain;
        LOOP
          FETCH devoirsLendemain INTO statutDevoirCourant;
          EXIT WHEN devoirsLendemain%NOTFOUND OR valretour = 0;
          IF valretour = 1 AND statutDevoirCourant = 0 THEN
            valretour:=0;
          END IF;
        END LOOP;
        CLOSE devoirsLendemain;
      ELSE 
        RAISE exceptionDate;
      END IF;
      RETURN valretour;
    EXCEPTION
      WHEN exceptionDate THEN
        DBMS_OUTPUT.PUT_LINE('Erreur, la date indiquée est incorrecte.');
        RETURN valretour;
    END;
    Par contre, toujours cette erreur d'Apex lorsque je compile l'autre fonction.

  6. #6
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Pour la procédure normale, voici un exemple basé sur ton fonctionnement de compteur de nb de jours à vérifier (ça je n'ai pas fait de vérif de boucle infinie ou autre), à toi de tracer.

    Il suffit simplement de passer par les dates, au moins pas de calcul à faire.

    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
     
    DECLARE
     v_date DATE := TRUNC(SYSDATE);
    BEGIN
    IF nomDuJour='monday' THEN 
      --On doit vérifier les devoirs pour les 5 prochains jours (Mardi, Mercredi, Jeudi, Vendredi, Samedi)
      nbJoursVerifies:=5;
    ELSIF nomDuJour='tuesday' THEN
      --On doit vérifier les devoirs pour les 4 prochains jours (Mercredi, Jeudi, Vendredi, Samedi)
      nbJoursVerifies:=4;
    ELSIF nomDuJour='wednesday' THEN
      --On doit vérifier les devoirs pour les 3 prochains jours (Jeudi, Vendredi, Samedi)
      nbJoursVerifies:=3;
    ELSIF nomDuJour='thursday' THEN
      --On doit vérifier les devoirs pour les 2 prochains jours (Vendredi, Samedi)
      nbJoursVerifies:=2;
    ELSIF nomDuJour='friday' THEN
      --On doit vérifier les devoirs pour le lendemain (Samedi)
      nbJoursVerifies:=1;
    ELSIF nomDuJour='saturday' THEN
      --On doit vérifier les devoirs pour la semaine suivante
      nbJoursVerifies:=6;
    	v_date := v_date + 1;--On fait comme si on était dimanche [A modifier, partiellement incorrect]
    ELSE
     --On est dimanche, on doit vérifier les devoirs pour la semaine suivante.
     nbJoursVerifies:=6;
    END IF;
     
    cpt := 0;
    WHILE (termine = 1 AND cpt < nbJoursVerifies)
    LOOP
    	v_date := v_date + 1;
    	termine := statutDevoirs(TO_CHAR(v_date, 'DDMMYYYY')); --Appel à la fonction unitaire
    	cpt:=cpt+1;
    END LOOP;
     
    RETURN termine;

  7. #7
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    devrait suffire non ? Ton astuce est assez.. astucieuse il faudrait étudier la complexité pour savoir quelle méthode serait la plus avantageuse. Au fond, la requête est la même.
    Alors là, y'a pas à chercher : Un select est plus avantageux qu'un curseur
    Garde ce que tu as fait pour ton projet, mais retiens le select avec l'exception, c'est la meilleure méthode qui existe.

    Méthode avec for loop, pour le exit
    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
    CURSOR devoirsLendemain IS
      SELECT statutDevoir
      FROM DEVOIR
      WHERE dateDevoir = dateChoisie;
     
    BEGIN
      --On vérifie que la date respecte le bon format (utilisation d'une expression régulière)
      IF REGEXP_LIKE (dateChoisie, '[01-31][01-12]2[0-9][1-9][0-9]') THEN
     
        --On part du principe que les devoirs sont terminés.
        --Dès que l'on rencontre un devoir non terminé, on retourne 0.
        FOR r IN devoirsLendemain;
        LOOP
        	IF valretour = 1 AND r.statutDevoir = 0 
          THEN
            valretour:=0;
          	EXIT;
          END IF;
        END LOOP;
      ELSE 
        RAISE exceptionDate;
      END IF;
     
      RETURN valretour;

  8. #8
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 36
    Par défaut
    En effet c'est beaucoup moins prise de tête que de gérer soi même les incrémentations de jours, même si je reste persuadé que c'est réalisable je dois juste faire des erreurs

    J'ai réussi à compiler, mais alors c'est à n'y rien comprendre !

    La première fois, j'ai le fameux message d'erreur.
    J'enlève la ligne correspondant à l'appel de la fonction unitaire, je compile.
    Je la remet, sans le commentaire et sans indentation, cela compile.
    J'indente la ligne, j'ai de nouveau le message d'erreur.
    Je met le point virgule du END à une nouvelle ligne, je compile.
    J'ajoute le commentaire, je compile.
    Je remet le point virgule derrière le END, je compile toujours.

    Bon.. on va dire que l'essentiel est là (Maintenant je vais voir si la fonction est correcte et répond bien aux attentes) mais je dois dire que je ne comprend vraiment pas ! Pourquoi cela ne compile pas puis soudainement cela compile ? ...

    Si je sélectionne toute ma fonction, que je fais "run" j'ai de nouveau le message d'erreur, mais en me plaçant à la fin du bloc, derrière le point virgule cela fonctionne.

    En tout cas je te remercie pour ton aide précieuse, tu as passé pas mal de temps à me répondre c'est sympa

    Si jamais j'ai un autre problème je posterais dans la continuité de ce topic, mais j'essayerais bien avant de le résoudre seul

    Edit: Ok pour le select, ça me paraît aussi moins demandeur en ressources. Je vais voir si ma méthode est réactive, si elle ne l'est pas je changerais !

    Tu m'incites vraiment à oublier mon Open Cursor
    Le EXIT WHEN moncurseur%NOTFOUND OR valRetour = 0 fonctionne quand même non ?

  9. #9
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Le EXIT WHEN moncurseur%NOTFOUND OR valRetour = 0 fonctionne quand même non ?
    Bien sur, je ne donnais le FOR LOOP que pour indication.

    Sinon, pour tes erreurs de compilation, fais un SHOW ERROR pour connaitre le problème.

  10. #10
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 36
    Par défaut
    Bien sur, je ne donnais le FOR LOOP que pour indication.
    Ok
    Sinon, pour tes erreurs de compilation, fais un SHOW ERROR pour connaitre le problème
    Parles-tu des vues USER_ERRORS, ALL_ERRORS ou encore DBA_ERRORS ?

    J'avais regardé hier, elles sont toutes vides.

  11. #11
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par Nicolus Voir le message
    Edité: On ne peut pas supprimer un message ? :p
    Si, tu cliques sur "Editer", puis dans l'encadré Suppression, tu sélectionnes "Suppression logique".

  12. #12
    McM
    McM est déconnecté
    Expert confirmé

    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Juillet 2003
    Messages
    4 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Juillet 2003
    Messages : 4 580
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par Nicolus Voir le message
    Parles-tu des vues USER_ERRORS, ALL_ERRORS ou encore DBA_ERRORS ?

    J'avais regardé hier, elles sont toutes vides.
    Tu compiles comment ? en sql+ , sous toad, sqldevelopper ?
    http://www.developpez.net/forums/d21...ge-show-error/

  13. #13
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 36
    Par défaut
    Je compile sous l'interface d'oracle.

    Je n'aime pas trop SqlDevelopper, je le trouve trop gourmand en ressources et il ne m'apporte rien de plus..

    Sinon en recours je peux utiliser sql+ dans mon terminal, mais je ne le maîtrise pas.

  14. #14
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 953
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 953
    Par défaut
    Ce que tu appelles l'interface d'oracle c'est une interface web développé en apex pour construire des applis web.
    Par contre pour créer tes procédures stokées ce n'est pas le mieux, d'ailleurs ton erreur de base
    The requested URL /apex/wwv_flow.show was not found on this server
    te masquait les erreurs de ton code.

    Utilises sql+, pour plus de facilité, place ton code dans un fichier texte, tonfichier.sql, puis depuis l'invite de commande déplace toi jusqu'au dossier dans lequel tu as créé le fichier. Ensuite tu te connectes à sql+ puis pour appeler le fichier tu fais :
    Après l'IHM apex est bien pour voir tes tables, tes procédures, faire quelques requêtes voir si le code a bien fonctionné, mais pas trop pour debugger du PL/SQL.

    Sqldeveloper est plus lourd c'est vrai, mais lui c'est un vrai environnement de développement PL/SQL.

  15. #15
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 36
    Par défaut
    Bonjour,

    Sous sqlplus le même code qui me fait une erreur apex ne me donne aucune erreur..

    Je lance sql plus depuis mon dossier, je m'identifie avec le même compte.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    @test.sql
    .
    SHOW ERRORS
    No errors.
    Je vais dans l'object browser pour vérifier, je n'ai pas ma fonction.


    Autrement ok pour l'interface Apex, en gros c'est le concurrent propriétaire de phpmyadmin sous mysql. Mais bon c'est dommage que ce ne soit pas optimisé pour le pl/sql, j'aime bien les interfaces simples et légères...

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 21/03/2011, 11h54
  2. Problème pour la création d'une fonction
    Par jipé95 dans le forum C
    Réponses: 5
    Dernier message: 10/12/2006, 14h28
  3. Réponses: 16
    Dernier message: 24/10/2006, 21h37
  4. Création d'une fonction sans paramètre?
    Par falcon dans le forum Oracle
    Réponses: 3
    Dernier message: 13/12/2004, 11h32
  5. Réponses: 14
    Dernier message: 09/04/2004, 13h44

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