Précédent   Forum des professionnels en informatique > Bases de données > Oracle > PL/SQL
PL/SQL Forum d'entraide sur le PL/SQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 24/12/2010, 16h18   #1
Nouveau Membre du Club
 
Inscription : décembre 2010
Messages : 36
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 36
Points : 28
Points : 28
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:

Citation:
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 :
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 :
CREATE OR REPLACE TYPE  "TYPE_TAB" IS VARRAY(12) OF VARCHAR2(2);
Nicolus est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/12/2010, 21h47   #2
McM
Expert Confirmé Sénior
 
Inscription : juillet 2003
Messages : 3 437
Détails du profil
Informations forums :
Inscription : juillet 2003
Messages : 3 437
Points : 4 173
Points : 4 173
Attention à tes déclarations et tes calculs sur les varchar2
exemple
Code :
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 :
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 :
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 ?
__________________
More Code : More Bugs. Less Code : Less Bugs
McM est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/12/2010, 10h50   #3
Nouveau Membre du Club
 
Inscription : décembre 2010
Messages : 36
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 36
Points : 28
Points : 28
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 :
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 :
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 :
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;
Nicolus est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/12/2010, 11h50   #4
McM
Expert Confirmé Sénior
 
Inscription : juillet 2003
Messages : 3 437
Détails du profil
Informations forums :
Inscription : juillet 2003
Messages : 3 437
Points : 4 173
Points : 4 173
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 :
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;
__________________
More Code : More Bugs. Less Code : Less Bugs
McM est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/12/2010, 12h14   #5
Nouveau Membre du Club
 
Inscription : décembre 2010
Messages : 36
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 36
Points : 28
Points : 28
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 :
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 :
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.
Nicolus est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/12/2010, 12h25   #6
McM
Expert Confirmé Sénior
 
Inscription : juillet 2003
Messages : 3 437
Détails du profil
Informations forums :
Inscription : juillet 2003
Messages : 3 437
Points : 4 173
Points : 4 173
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 :
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;
__________________
More Code : More Bugs. Less Code : Less Bugs
McM est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 27/12/2010, 12h32   #7
McM
Expert Confirmé Sénior
 
Inscription : juillet 2003
Messages : 3 437
Détails du profil
Informations forums :
Inscription : juillet 2003
Messages : 3 437
Points : 4 173
Points : 4 173
Citation:
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 :
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;
__________________
More Code : More Bugs. Less Code : Less Bugs
McM est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/12/2010, 12h50   #8
Nouveau Membre du Club
 
Inscription : décembre 2010
Messages : 36
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 36
Points : 28
Points : 28
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 ?
Nicolus est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/12/2010, 13h58   #9
McM
Expert Confirmé Sénior
 
Inscription : juillet 2003
Messages : 3 437
Détails du profil
Informations forums :
Inscription : juillet 2003
Messages : 3 437
Points : 4 173
Points : 4 173
Citation:
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.
__________________
More Code : More Bugs. Less Code : Less Bugs
McM est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/12/2010, 14h01   #10
Nouveau Membre du Club
 
Inscription : décembre 2010
Messages : 36
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 36
Points : 28
Points : 28
Citation:
Bien sur, je ne donnais le FOR LOOP que pour indication.
Ok
Citation:
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.
Nicolus est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/12/2010, 20h49   #11
McM
Expert Confirmé Sénior
 
Inscription : juillet 2003
Messages : 3 437
Détails du profil
Informations forums :
Inscription : juillet 2003
Messages : 3 437
Points : 4 173
Points : 4 173
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".
__________________
More Code : More Bugs. Less Code : Less Bugs
McM est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/12/2010, 20h52   #12
McM
Expert Confirmé Sénior
 
Inscription : juillet 2003
Messages : 3 437
Détails du profil
Informations forums :
Inscription : juillet 2003
Messages : 3 437
Points : 4 173
Points : 4 173
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/
__________________
More Code : More Bugs. Less Code : Less Bugs
McM est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/12/2010, 22h47   #13
Nouveau Membre du Club
 
Inscription : décembre 2010
Messages : 36
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 36
Points : 28
Points : 28
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.
Nicolus est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/12/2010, 23h10   #14
Membre Expert
 
Inscription : août 2008
Messages : 1 271
Détails du profil
Informations forums :
Inscription : août 2008
Messages : 1 271
Points : 1 929
Points : 1 929
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
Citation:
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.
skuatamad est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/12/2010, 09h49   #15
Nouveau Membre du Club
 
Inscription : décembre 2010
Messages : 36
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 36
Points : 28
Points : 28
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 :
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...
Nicolus est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 11h17.


 
 
 
 
Partenaires

Hébergement Web