Précédent   Forum des professionnels en informatique > Bases de données > PostgreSQL
PostgreSQL Forum PostgreSQL. Avant de poster -> F.A.Q PostGreSQL Tutoriels PostGreSQL
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 07/05/2011, 14h09   #1
Membre éclairé
 
Homme
Développeur .NET
Inscription : juin 2005
Messages : 590
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 36
Localisation : France

Informations professionnelles :
Activité : Développeur .NET
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : juin 2005
Messages : 590
Points : 356
Points : 356
Envoyer un message via ICQ à giova_fr
Par défaut plpgsql retournant un tableau = probleme

Bonjour.

Pour simplifier mon probleme, disons que je tente de créer une fonction qui fasse une requette et me retourne le resultat. (evidemment c'est plus compliqué que ca en vrai)

En me basant sur les docs trouvées, ma fonction retourne un record. Mais ca ne me va pas du tout, car ce qui m'est retourné n'a qu'une seule colonne contenant le record, du coup, mon client derriere ne sait pas lire le resultat. Or moi je voudrais récupérer les lignes de mon tableau intégralement !!!

Je suis programmeur, pas DBA aussi désolé si ma question semble stupide...

Lorsque j'appelle ma fonction, je voudrais que ce soit comme ci je faisais cette requette (XXX etant la valeur de mon argument) :
Code :
SELECT * FROM employe WHERE employe.id = XXX;
Et voici ma fonction actuelle qui ne va pas :
Code :
1
2
3
4
5
6
7
8
9
10
11
CREATE OR REPLACE FUNCTION "GetEmploye"(userid integer)
  RETURNS record AS
$BODY$
DECLARE
   rec record;
BEGIN
   SELECT * FROM employe  WHERE  employe.id  =userid INTO rec;              
   RETURN rec;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;
Auriez vous un lien/exemple pour me montrer le plus simplement du monde, comme on parlerait à un petit enfant, comment atteindre l'objectif?

Un grand merci d'avance.
giova_fr est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/05/2011, 14h36   #2
Membre éclairé
 
Homme
Développeur .NET
Inscription : juin 2005
Messages : 590
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 36
Localisation : France

Informations professionnelles :
Activité : Développeur .NET
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : juin 2005
Messages : 590
Points : 356
Points : 356
Envoyer un message via ICQ à giova_fr
J'ai fini par hasard, à tomber sur la réponse :

Ceci me retournera bien le meme type que si je faisais un simple select :

Code :
1
2
3
4
5
6
7
8
9
10
11
CREATE OR REPLACE FUNCTION "GetEmploye"(userid integer)
  RETURNS employe AS
$BODY$
DECLARE
   rec employe%ROWTYPE;
BEGIN
   SELECT * FROM employe  WHERE  employe.id  =userid INTO rec;              
   RETURN rec;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;
giova_fr est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 08/05/2011, 21h41   #3
Membre éclairé
 
Homme
Développeur .NET
Inscription : juin 2005
Messages : 590
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 36
Localisation : France

Informations professionnelles :
Activité : Développeur .NET
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : juin 2005
Messages : 590
Points : 356
Points : 356
Envoyer un message via ICQ à giova_fr
Anciennement flaggé "resolu" je réouvre le dossier car la méthode employé pose un nouveau probleme.

Si la requette ne trouve pas de résultat, ma fonction ne retourne pas un resultat "null" mais une ligne vide !

Exemple avec un userid qui ne mene nullepart :

Code :
SELECT count(*) FROM "GetEmploye"(123)
va me retourner 1 alors que l'employe 123 n'existe pas !

En somme ce que j'aimerai, c'est que ma fonctionne simule rigoureusement le comportement d'une requette. J'ai du mal a comprendre pourquoi les choses se compliquent de la sorte...

J'ai biensur modifié ma fonction pour qu'elle retourne un null si elle ne trouve pas de résultat, mais ca ne change rien au probleme.

Comment faire SVP ?
giova_fr est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/05/2011, 08h04   #4
Membre confirmé
 
Homme
Inscription : janvier 2006
Messages : 227
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Corse (Corse)

Informations forums :
Inscription : janvier 2006
Messages : 227
Points : 239
Points : 239
bonjour,
peut-être en rajoutant une condition

Code :
1
2
3
4
5
BEGIN
IF userid IN SELECT id FROM employe then
   SELECT * FROM employe  WHERE  employe.id  =userid INTO rec;              
   RETURN rec;
end IF;
xavier-Pierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/05/2011, 08h38   #5
Expert Confirmé
 
Homme
Inscription : septembre 2006
Messages : 2 291
Détails du profil
Informations personnelles :
Sexe : Homme

Informations forums :
Inscription : septembre 2006
Messages : 2 291
Points : 2 737
Points : 2 737
Après un SELECT, NOT FOUND sera vrai s'il n'y a pas de résultat, donc
Code :
1
2
3
4
5
6
7
 
SELECTIF NOT found then
 -- no record found: return null, raise an exception, …
else
 ...
end;
JeitEmgie est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/05/2011, 14h36   #6
Modérateur
 
Inscription : octobre 2008
Messages : 1 505
Détails du profil
Informations personnelles :
Localisation : France, Paris (Île de France)

Informations forums :
Inscription : octobre 2008
Messages : 1 505
Points : 2 034
Points : 2 034
Citation:
Envoyé par giova_fr Voir le message
En somme ce que j'aimerai, c'est que ma fonctionne simule rigoureusement le comportement d'une requette. J'ai du mal a comprendre pourquoi les choses se compliquent de la sorte...

J'ai biensur modifié ma fonction pour qu'elle retourne un null si elle ne trouve pas de résultat, mais ca ne change rien au probleme.

Comment faire SVP ?
C'est parce que retourner un enregistrement null n'est pas la même chose que de ne rien retourner du tout.
Mais le plus simple ici serait d'utiliser RETURN QUERY qui est pile fait pour ça:
Code :
 RETURN QUERY SELECT * FROM employe  WHERE  employe.id  =userid;
Sinon pour ce genre de fonction mono-instruction, on utilise généralement le langage sql plutôt que plpgsql car il n'y a rien de procédural, exemple:
Code :
1
2
CREATE FUNCTION getemp(int) returns emp AS 'select * from emp where id=$1'
 LANGUAGE sql;
estofilo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/05/2011, 17h41   #7
Membre éclairé
 
Homme
Développeur .NET
Inscription : juin 2005
Messages : 590
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 36
Localisation : France

Informations professionnelles :
Activité : Développeur .NET
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : juin 2005
Messages : 590
Points : 356
Points : 356
Envoyer un message via ICQ à giova_fr
Merci beaucoup pour vos réponses.

estofilo vous venez de me donner une excelente réponse, explicative et claire.

@JeitEmgie> j'avais biensur essayé ta méthode, mais ca ne marchait pas, il me retournait quand meme une ligne vide, sans doute à cause du type de sortie de ma fonction.

@xavier-Pierre> impossible, la fonction DOIT retourner quelque chose, sinon ca plante à l'execution, c'est ainsi...

Ma fonction ne fait pas une simple requette, elle en fait plusieurs, et en fonction des résultats authorise ou non la requette finale qui sera retournée.

Je n'ai d'ailleur pas encore tout à fait compris l'interret d'une fonction SQL, j'imagine pour une question de droits que je maitrise tres tres mal pour le moment, mais bon c'est un autre sujet...

Je vais de ce pas tester return QUERY
giova_fr est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/05/2011, 18h17   #8
Membre éclairé
 
Homme
Développeur .NET
Inscription : juin 2005
Messages : 590
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 36
Localisation : France

Informations professionnelles :
Activité : Développeur .NET
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : juin 2005
Messages : 590
Points : 356
Points : 356
Envoyer un message via ICQ à giova_fr
arg ca se passe toujours tres mal...

Je reprécise au passage que dans mes exemples, je simplifie ma fonction au max, n'imaginez pas qu'elle ne fasse qu'une simple requette !

Au debut j'ai fais mon simple return Query ...
mais le compilateur n'etait pas content, disant en gros que ma fonction doit retourner un setof :

Code :
1
2
3
4
5
6
7
8
9
10
CREATE OR REPLACE FUNCTION "GetEmploye"(userid integer)
  RETURNS employe AS
$BODY$
DECLARE
   rec employe%ROWTYPE;
BEGIN
  RETURN QUERY SELECT * FROM employe  WHERE  employe.id  =userid;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;
donne

Citation:
ERROR: RETURN must specify a record or row variable in function returning tuple at or near "QUERY"
ok ca me parait plutot logique, donc je change la signature de la fonction :

Code :
1
2
3
4
5
6
7
8
9
10
CREATE OR REPLACE FUNCTION "GetEmploye"(userid integer)
  RETURNS SETOF employe AS
$BODY$
DECLARE
   rec employe%ROWTYPE;
BEGIN
  RETURN QUERY SELECT * FROM employe  WHERE  employe.id  =userid;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;
Et là il me dit l'inverse on dirait, je n'y comprend rien :
Citation:
ERROR: RETURN cannot have a parameter in function returning set; use RETURN NEXT at or near "QUERY"
giova_fr est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/05/2011, 18h24   #9
Modérateur
 
Inscription : octobre 2008
Messages : 1 505
Détails du profil
Informations personnelles :
Localisation : France, Paris (Île de France)

Informations forums :
Inscription : octobre 2008
Messages : 1 505
Points : 2 034
Points : 2 034
C'est quelle version de postgresql?
estofilo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/05/2011, 18h42   #10
Membre éclairé
 
Homme
Développeur .NET
Inscription : juin 2005
Messages : 590
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 36
Localisation : France

Informations professionnelles :
Activité : Développeur .NET
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : juin 2005
Messages : 590
Points : 356
Points : 356
Envoyer un message via ICQ à giova_fr
8.2.13 que je ne peux pas mettre à jour
giova_fr est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/05/2011, 19h00   #11
Modérateur
 
Inscription : octobre 2008
Messages : 1 505
Détails du profil
Informations personnelles :
Localisation : France, Paris (Île de France)

Informations forums :
Inscription : octobre 2008
Messages : 1 505
Points : 2 034
Points : 2 034
RETURN QUERY n'existait pas encore en 8.2.

Il faudrait donc utiliser RETURN NEXT autant de fois qu'il y a de lignes à retourner suivi de RETURN pour finir. Voir la doc plpgsql pour la version 8.2:
http://www.postgresql.org/docs/8.2/s...ENTS-RETURNING
estofilo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/05/2011, 14h59   #12
Membre éclairé
 
Homme
Développeur .NET
Inscription : juin 2005
Messages : 590
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 36
Localisation : France

Informations professionnelles :
Activité : Développeur .NET
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : juin 2005
Messages : 590
Points : 356
Points : 356
Envoyer un message via ICQ à giova_fr
Ca fonctionne enfin comme voulu merci

Je suis juste surpris de devoir encore appeller ma fonction ainsi :

Code :
SELECT * FROM "GetEmploye"(123);
Je m'attendais plus à devoir faire
Code :
SELECT "GetEmploye"(123);
giova_fr 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 12h45.


 
 
 
 
Partenaires

Hébergement Web