Précédent   Forum des professionnels en informatique > Bases de données > Oracle > SQL
SQL Forum d'entraide sur le SQL pour Oracle
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 18/12/2007, 18h45   #1
Invité de passage
 
Inscription : février 2007
Messages : 26
Détails du profil
Informations personnelles :
Âge : 24

Informations forums :
Inscription : février 2007
Messages : 26
Points : 3
Points : 3
Par défaut [PL/SQL] Problème gestion d'éxception

Bonjour à tous,

J' ai un problème pour gérer une éxception dans une fonction en PL/SQL.
Ma fonction parcours une table, doit me selectionner la plus grande date contenue dans cette table pour un client donné et la soustraire à la date du jour. Le code de cette fonction marche tres bien quand je l'appelle en JAVA. Le problème, c'est quand le client n'est pas encore dans la table, c'est-à-dire qu'il n'y a pas de date lui corréspondant, un éxception est levée sous Eclipse, qui m'indique qu'aucune valeur n'est retournée, mais le programme continu à tourner sans problème. Je voudrais qu'il n'y ait plus d'affichage.
C'est pourquoi j'ai décidé de gérer l'éxception en PL/SQL.

Voici mon 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
 
CREATE OR REPLACE FUNCTION EmpecheVote (loginUtil IN CLIENT.login%type) RETURN INTEGER IS 
BEGIN 
DECLARE 
presant INTEGER;
i INTEGER;
k INTEGER;
temp DATE;
CURSOR monC IS SELECT DateNote FROM TempIndFilm WHERE loginNoteur = loginUtil;
TYPE TableDate IS TABLE Of DATE INDEX BY BINARY_INTEGER;
tabdate TableDate;
BEGIN
presant:=-1;
k:=0;
i:=0;
FOR elt IN monC 
LOOP
tabdate(i):=TO_DATE(elt.DateNote);
i:=i+1;
END LOOP;
temp:=tabDate(0);
FOR i IN 1..tabdate.COUNT() -1 
LOOP
IF tabdate(i) > temp THEN
temp:=tabdate(i); 
END IF;
END LOOP;
IF (SYSDATE - temp>1) THEN
presant:=1;
END IF;
EXCEPTION 
WHEN NO_DATA_FOUND THEN
presant:=0;
RETURN presant;
END;
END EmpecheVote;
/
Le probleme avec cette exception, c'est que maintenant mon code ne marche plus, la valeur retournée est incorrecte, il me retourne tout le temps 0.

J'aimerais savoir si l'erreur vient de la synthaxe de mon éxception ou si elle est male placée...
Rydley est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/12/2007, 19h03   #2
Rédacteur/Modérateur
 
Avatar de orafrance
 
Inscription : janvier 2004
Messages : 15 861
Détails du profil
Informations personnelles :
Âge : 35

Informations forums :
Inscription : janvier 2004
Messages : 15 861
Points : 16 212
Points : 16 212
il manque un RETURN presant non ?

Sinon, à ce que je vois l'exception ne se déclenchera jamais

c'est monC%ROWCOUNT éventuellement que tu devrais utiliser.

PS : presant s'écrit present
orafrance est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/12/2007, 20h41   #3
Expert Confirmé Sénior
 
Avatar de mnitu
 
Homme Marius Nitu
Ingénieur développement logiciels
Inscription : octobre 2007
Messages : 3 319
Détails du profil
Informations personnelles :
Nom : Homme Marius Nitu
Localisation : France, Marne (Champagne Ardenne)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : octobre 2007
Messages : 3 319
Points : 5 837
Points : 5 837
Trop de code, trop des variables, trop des exceptions, etc.
L'exception NO_DATA_FOUND n'est jamais levé pour un curseur, il faut faire un «*select ... into*» pour ça.
Select Max(...) permet d'obtenir la plus grande date par client pas besoin de recoder l'algorithme.
Vue le code que vous avez posté vous avez du travaille à faire avec SQL
mnitu est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/12/2007, 21h46   #4
Invité de passage
 
Inscription : février 2007
Messages : 26
Détails du profil
Informations personnelles :
Âge : 24

Informations forums :
Inscription : février 2007
Messages : 26
Points : 3
Points : 3
Le problème pour le select MAX, c'est que j'ai stockée les date en CHAR dans la table et non pas en DATE, c'est pourquoi j'utilise un tableau pour convertir les CHAR en DATE. Maintenant, est-ce que la fonction MAX marche aussi avec les variables de tye CHAR.

Sinon orafrance, j'ai essayé d'utilisé monC%ROWCOUNT comme ceci :

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
 
CREATE OR REPLACE FUNCTION EmpecheVote (loginUtil IN CLIENT.login%type) RETURN INTEGER IS 
BEGIN 
DECLARE 
presant INTEGER;
i INTEGER;
k INTEGER;
temp DATE;
CURSOR monC IS SELECT DateNote FROM TempIndFilm WHERE loginNoteur = loginUtil;
TYPE TableDate IS TABLE Of DATE INDEX BY BINARY_INTEGER;
tabdate TableDate;
BEGIN
presant:=-1;
k:=0;
i:=0;
IF monC%ROWCOUNT IS NULL THEN 
presant:=0;
ELSE 
	FOR elt IN monC 
	LOOP
	tabdate(i):=TO_DATE(elt.DateNote);
	i:=i+1;
	END LOOP;
	temp:=tabDate(0);
	FOR i IN 1..tabdate.COUNT() -1 
	LOOP
	IF tabdate(i) > temp THEN
	temp:=tabdate(i); 
	END IF;
	END LOOP;
	IF (SYSDATE - temp>1) THEN presant:=1;
	END IF;
END IF;
RETURN presant;
END;
END EmpecheVote;
/
A l'éxécution avec Eclipse, j'ai une éxception qui est levée: "curseur non valide" à la ligne du ROWCOUNT.
Rydley est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/12/2007, 23h17   #5
Rédacteur/Modérateur
 
Avatar de orafrance
 
Inscription : janvier 2004
Messages : 15 861
Détails du profil
Informations personnelles :
Âge : 35

Informations forums :
Inscription : janvier 2004
Messages : 15 861
Points : 16 212
Points : 16 212
et MAX(TO_DATE(colonne)) ? T'es juste en train de réinventer la roue
orafrance est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/12/2007, 02h31   #6
Membre éprouvé
 
Inscription : décembre 2007
Messages : 354
Détails du profil
Informations personnelles :
Localisation : France

Informations forums :
Inscription : décembre 2007
Messages : 354
Points : 408
Points : 408
Citation:
Envoyé par orafrance Voir le message
et MAX(TO_DATE(colonne)) ? T'es juste en train de réinventer la roue
En plus ce n'est pas bien de stocker les dates en char dans les tables
Michel SALAIS est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/12/2007, 11h07   #7
Expert Confirmé Sénior
 
Avatar de mnitu
 
Homme Marius Nitu
Ingénieur développement logiciels
Inscription : octobre 2007
Messages : 3 319
Détails du profil
Informations personnelles :
Nom : Homme Marius Nitu
Localisation : France, Marne (Champagne Ardenne)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : octobre 2007
Messages : 3 319
Points : 5 837
Points : 5 837
Citation:
Envoyé par Rydley Voir le message
...
Sinon orafrance, j'ai essayé d'utilisé monC%ROWCOUNT comme ceci :

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
 
CREATE OR REPLACE FUNCTION EmpecheVote (loginUtil IN CLIENT.login%type) RETURN INTEGER IS 
BEGIN 
DECLARE 
presant INTEGER;
i INTEGER;
k INTEGER;
temp DATE;
CURSOR monC IS SELECT DateNote FROM TempIndFilm WHERE loginNoteur = loginUtil;
TYPE TableDate IS TABLE Of DATE INDEX BY BINARY_INTEGER;
tabdate TableDate;
BEGIN
presant:=-1;
k:=0;
i:=0;
IF monC%ROWCOUNT IS NULL THEN 
presant:=0;
ELSE 
	FOR elt IN monC 
	LOOP
	tabdate(i):=TO_DATE(elt.DateNote);
	i:=i+1;
	END LOOP;
	temp:=tabDate(0);
	FOR i IN 1..tabdate.COUNT() -1 
	LOOP
	IF tabdate(i) > temp THEN
	temp:=tabdate(i); 
	END IF;
	END LOOP;
	IF (SYSDATE - temp>1) THEN presant:=1;
	END IF;
END IF;
RETURN presant;
END;
END EmpecheVote;
/
A l'éxécution avec Eclipse, j'ai une éxception qui est levée: "curseur non valide" à la ligne du ROWCOUNT.
C'est normal. Le curseur n'est pas ouvert. En plus le ROWCOUNT n'est jamais null. Et tu continue a copier le données dans un tableau inutilement. Cette fonction n’a pas besoin de plus de 5 lignes de code.
Bon tu progresse déjà il n’y plus l’exception NO_DATA_FOUND. Elimine le tableau tabData, le variables i, k, temp, employe Max et tu verra.
mnitu est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/12/2007, 11h30   #8
McM
Expert Confirmé Sénior
 
Inscription : juillet 2003
Messages : 3 453
Détails du profil
Informations forums :
Inscription : juillet 2003
Messages : 3 453
Points : 4 215
Points : 4 215
Le mieux est de tout faire dans 1 select

Il faut bien déterminer les règles :
De ce que j'ai vu, il y a 3 valeurs de retour
0 Si pas de ligne
-1 Si le max date de plus de 1 jour
1 Si le max date de moins de 1 jour (ou plus tard qu'aujourdh'ui)

Un petit decode pour sortir ça.
Avec
Count(*) pour avoir le nb de lignes
Sign(a-b) qui renvoit 1 sur a>b
Max(to_date(date_en_char, 'DD/MM/YYYY'))

Ou alors utiliser un CASE (Plus simple à coder et à lire)
__________________
More Code : More Bugs. Less Code : Less Bugs
McM est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/12/2007, 19h43   #9
Invité de passage
 
Inscription : février 2007
Messages : 26
Détails du profil
Informations personnelles :
Âge : 24

Informations forums :
Inscription : février 2007
Messages : 26
Points : 3
Points : 3
C'est bon j'ai reussi a résoudre mon problème. J'ai utilisé ce que m'a dit orafrance, j'ai fait un MAX(TO_DATE(colonne)), ce qui a grandement simplifiée ma requête. Merci a tous pour votre aide.

Voici mon code final:

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
CREATE OR REPLACE FUNCTION EmpecheVote (loginUtil IN CLIENT.login%type) RETURN INTEGER IS 
BEGIN 
DECLARE 
presant INTEGER;
temp DATE;
dateNote DATE;
BEGIN
presant:=-1;
SELECT MAX (TO_DATE (DateNote)) INTO dateNote FROM TempIndFilm WHERE loginNoteur = loginUtil;
 
IF dateNote IS NULL THEN 
presant:=0;
ELSE 
	temp:=dateNote;
	IF (SYSDATE - temp>1) THEN presant:=1;
	END IF;
END IF;
RETURN presant;
END;
END EmpecheVote;
/
Rydley est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/12/2007, 21h09   #10
Expert Confirmé Sénior
 
Avatar de mnitu
 
Homme Marius Nitu
Ingénieur développement logiciels
Inscription : octobre 2007
Messages : 3 319
Détails du profil
Informations personnelles :
Nom : Homme Marius Nitu
Localisation : France, Marne (Champagne Ardenne)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : octobre 2007
Messages : 3 319
Points : 5 837
Points : 5 837
Il reste encore trop des variables et trop de code. Nvl permet de traiter les nulles, Decode ou Case permet de éliminer les If et le Begin suivi de Declare et de Begin laisse une mauvais impression.
mnitu est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/12/2007, 12h43   #11
McM
Expert Confirmé Sénior
 
Inscription : juillet 2003
Messages : 3 453
Détails du profil
Informations forums :
Inscription : juillet 2003
Messages : 3 453
Points : 4 215
Points : 4 215
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CREATE OR REPLACE FUNCTION EmpecheVote (loginUtil IN CLIENT.login%TYPE) RETURN INTEGER IS 
	presant INTEGER;
BEGIN
	presant:=-1;
	BEGIN
		SELECT (CASE WHEN COUNT(*) = 0 THEN 0
			WHEN MAX(TO_DATE (DateNote)) - SYSDATE > 1 THEN 1
			ELSE -1 END)  AS presant
		INTO presant
		FROM TempIndFilm 
		WHERE loginNoteur = loginUtil;
	EXCEPTION WHEN OTHERS THEN NULL;
	END;
 
	RETURN presant;
 
END EmpecheVote;
/
__________________
More Code : More Bugs. Less Code : Less Bugs
McM est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/12/2007, 13h40   #12
Expert Confirmé Sénior
 
Avatar de mnitu
 
Homme Marius Nitu
Ingénieur développement logiciels
Inscription : octobre 2007
Messages : 3 319
Détails du profil
Informations personnelles :
Nom : Homme Marius Nitu
Localisation : France, Marne (Champagne Ardenne)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : octobre 2007
Messages : 3 319
Points : 5 837
Points : 5 837
Citation:
Envoyé par McM Voir le message
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CREATE OR REPLACE FUNCTION EmpecheVote (loginUtil IN CLIENT.login%TYPE) RETURN INTEGER IS 
	presant INTEGER;
BEGIN
	presant:=-1;
	BEGIN
		SELECT (CASE WHEN COUNT(*) = 0 THEN 0
			WHEN MAX(TO_DATE (DateNote)) - SYSDATE > 1 THEN 1
			ELSE -1 END)  AS presant
		INTO presant
		FROM TempIndFilm 
		WHERE loginNoteur = loginUtil;
	EXCEPTION WHEN OTHERS THEN NULL;
	END;
 
	RETURN presant;
 
END EmpecheVote;
/
When OTHERS THEN NULL ça j'aime pas du tout
mnitu est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/12/2007, 14h00   #13
McM
Expert Confirmé Sénior
 
Inscription : juillet 2003
Messages : 3 453
Détails du profil
Informations forums :
Inscription : juillet 2003
Messages : 3 453
Points : 4 215
Points : 4 215
__________________
More Code : More Bugs. Less Code : Less Bugs
McM est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/12/2007, 15h40   #14
Expert Confirmé Sénior
 
Avatar de mnitu
 
Homme Marius Nitu
Ingénieur développement logiciels
Inscription : octobre 2007
Messages : 3 319
Détails du profil
Informations personnelles :
Nom : Homme Marius Nitu
Localisation : France, Marne (Champagne Ardenne)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : octobre 2007
Messages : 3 319
Points : 5 837
Points : 5 837
Citation:
Envoyé par McM Voir le message
TKyte
Citation:
1)
A when others is almost always a BUG unless it is immediately followed by a RAISE.

The point of an exception block is to catch exceptional conditions you are EXPECTING,
handle them gracefully and continue.

For example, lets say you have a procedure that will either INSERT a new record or UPDATE
an existing one depending on whether or not it exists. You could code:

begin
insert into t ( columns.... ) values ( values ..... );
exception
when dup_val_on_index then -- record already exists, lets update it
update t set .... = .... where ....;
end;


Now, if that was coded:

begin
insert into t ( columns.... ) values ( values ..... );
exception
when dup_val_on_index then -- record already exists, lets update it
update t set .... = .... where ....;
when others then
null;
end;


that would be a bug. The when others would fire upon some spurious -- un-expected error
and the record would be neither added nor updated. It would be skipped.

Same with your routines, if you have a when others -- and don't do anything meaningful in
it (eg: email yourself a notification that it failed, log a message using utl_file or an
autonomous transaction, etc -- it is an error that will go undetected.

I truly wish we didn't even support WHEN OTHERS.
You should only catch the exceptions you are expecting and can do something about. Let
the others propagate out so you can detect them (so you see them)
ou comme on le dit : "it's poor programming style".
mnitu est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/12/2007, 15h44   #15
Rédacteur/Modérateur
 
Avatar de orafrance
 
Inscription : janvier 2004
Messages : 15 861
Détails du profil
Informations personnelles :
Âge : 35

Informations forums :
Inscription : janvier 2004
Messages : 15 861
Points : 16 212
Points : 16 212
Comme je l'ai déjà dit, c'est très pratique pour faire un trigger ON_LOGON et qu'on ne souhaite pas qu'une exception imprévu interdise la connexion. C'est certes pas très joli mais certaines sociétés ne peuvent pas se permettre d'avoir des dysfonctionnements lourd de conséquence à cause d'un bug mineur... le NULL par contre est pas top, vaut mieux logguer l'info quelquepart (l'alert.log par exemple) pour pallier à une carence du code
orafrance est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/12/2007, 16h43   #16
Expert Confirmé Sénior
 
Avatar de mnitu
 
Homme Marius Nitu
Ingénieur développement logiciels
Inscription : octobre 2007
Messages : 3 319
Détails du profil
Informations personnelles :
Nom : Homme Marius Nitu
Localisation : France, Marne (Champagne Ardenne)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : octobre 2007
Messages : 3 319
Points : 5 837
Points : 5 837
Citation:
Envoyé par orafrance Voir le message
Comme je l'ai déjà dit, c'est très pratique pour faire un trigger ON_LOGON et qu'on ne souhaite pas qu'une exception imprévu interdise la connexion. C'est certes pas très joli mais certaines sociétés ne peuvent pas se permettre d'avoir des dysfonctionnements lourd de conséquence à cause d'un bug mineur... le NULL par contre est pas top, vaut mieux logguer l'info quelquepart (l'alert.log par exemple) pour pallier à une carence du code
Y compris pour un trigger ON LOGON j’ai peur que cella cache en fait le « nous n’avons pas bien testé ». Le problème avec WHEN OTHERS THEN NULL c’est qu’on est dans l’ignorance totale; souvent c’est un cache misère difficile a débuguer.
mnitu est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/12/2007, 16h50   #17
Rédacteur/Modérateur
 
Avatar de orafrance
 
Inscription : janvier 2004
Messages : 15 861
Détails du profil
Informations personnelles :
Âge : 35

Informations forums :
Inscription : janvier 2004
Messages : 15 861
Points : 16 212
Points : 16 212
c'est beau de savoir développer une solution bugless du 1° coup en prod

sur les bases de test t'as rarement les mêmes conditions d'utilisation qu'en prod notamment en ce qui concerne les connexions
orafrance est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/12/2007, 17h32   #18
Expert Confirmé Sénior
 
Avatar de mnitu
 
Homme Marius Nitu
Ingénieur développement logiciels
Inscription : octobre 2007
Messages : 3 319
Détails du profil
Informations personnelles :
Nom : Homme Marius Nitu
Localisation : France, Marne (Champagne Ardenne)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : octobre 2007
Messages : 3 319
Points : 5 837
Points : 5 837
Citation:
Envoyé par orafrance Voir le message
c'est beau de savoir développer une solution bugless du 1° coup en prod

sur les bases de test t'as rarement les mêmes conditions d'utilisation qu'en prod notamment en ce qui concerne les connexions
Je ne sais pas faire ça !
Mais si on emploie WHEN OTHERS THEN NULL on peut bien dire que ce code ne sert à rien parfois, c’est à dire quand une exception arrive, et donc logiquement s’en passer tranquillement.
mnitu est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/12/2007, 17h37   #19
Rédacteur/Modérateur
 
Avatar de orafrance
 
Inscription : janvier 2004
Messages : 15 861
Détails du profil
Informations personnelles :
Âge : 35

Informations forums :
Inscription : janvier 2004
Messages : 15 861
Points : 16 212
Points : 16 212
Citation:
Envoyé par mnitu Voir le message
Mais si on emploie WHEN OTHERS THEN NULL on peut bien dire que ce code ne sert à rien parfois
ou qu'on préfère privilégié la continuité de service plutôt que le code en question

Mais je confirme qu'un envoie de message dans l'alerte log plutôt qu'un "bête" NULL est plus intéressant
orafrance est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/12/2007, 13h58   #20
McM
Expert Confirmé Sénior
 
Inscription : juillet 2003
Messages : 3 453
Détails du profil
Informations forums :
Inscription : juillet 2003
Messages : 3 453
Points : 4 215
Points : 4 215
Citation:
Envoyé par mnitu Voir le message
Je ne sais pas faire ça !
Mais si on emploie WHEN OTHERS THEN NULL on peut bien dire que ce code ne sert à rien parfois, c’est à dire quand une exception arrive, et donc logiquement s’en passer tranquillement.
Pas du tout : En cas d'erreur sur le select, tu renvoies -1.
C'est un choix qu'on peut avoir ou pas.
__________________
More Code : More Bugs. Less Code : Less Bugs
McM est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 07h38.


 
 
 
 
Partenaires

Hébergement Web