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 14/06/2006, 13h57   #1
Invité de passage
 
Inscription : juin 2006
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2006
Messages : 8
Points : 0
Points : 0
Par défaut Instruction EXECUTE avec paramètres

Quelqu'un peut-il m'expliquer où se situe mon erreur:

Ceci fonctionne:
Code :
1
2
3
 
SELECT INTO member_info * FROM t_tmp_member;
RETURN member_info;
Cela ne fonctionne pas:
Code :
1
2
3
4
 
sql_select:='SELECT INTO ' || member_info || ' * FROM t_tmp_member;';
EXECUTE sql_select;
RETURN member_info;
et génère ce type d'erreur:
Code :
ERROR:  could NOT find array type FOR DATA type typ_member_alldetails
Un petit tour sur le Net ne m'a pas vraiment aidé

Une idée?

Merci d'avance!
@n@kin.be est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/06/2006, 08h35   #2
Membre chevronné
 
Avatar de gerald2545
 
Inscription : février 2003
Messages : 643
Détails du profil
Informations forums :
Inscription : février 2003
Messages : 643
Points : 660
Points : 660
je crois avoir vu dans la doc postgresql il n'y a pas longtemps que le SELECT INTO n'est pas supporté par la commande EXECUTE.
ce qui explique peut-être ton problème.
bonne journée
gerald2545 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/06/2006, 08h40   #3
Membre chevronné
 
Avatar de gerald2545
 
Inscription : février 2003
Messages : 643
Détails du profil
Informations forums :
Inscription : février 2003
Messages : 643
Points : 660
Points : 660
précision :
ta commande SELECT INTO ne te renverra que le dernier enregistrement récupéré par ta requête. Si tu veux tous les enregistrements retournés par ta requete, il faut boucler.
gerald2545 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/06/2006, 10h51   #4
Invité de passage
 
Inscription : juin 2006
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2006
Messages : 8
Points : 0
Points : 0
Citation:
je crois avoir vu dans la doc postgresql il n'y a pas longtemps que le SELECT INTO n'est pas supporté par la commande EXECUTE
Merci pour ta réponse Gerald, je n'avais pas vu ça dans la doc, ça serait bien en effet la cause de mon problème.

Citation:
ta commande SELECT INTO ne te renverra que le dernier enregistrement récupéré par ta requête
Aucun niveau à ce problème, elle ne doit retourner qu'un record

Je m'enfonce dans une impasse... En fait, pour "contourner" le problème rencontré et expliqué dans ce forum (sujet : Fonction: Retour d'un SET dynamique), j'ai trouvé une solution passant par une table temporaire et la déclaration d'un type. Cette solution fonctionne à merveille ... mais 1 seule fois car vu que je travaille avec un CREATE TEMP TABLE, je tombe dans le side effect de pl/pgsql qui me donne une erreur "relation with OID ###### does not exist" et pour laquelle on me recommande d'utiliser EXECUTE pour les accès à la table... si mon SELECT INTO ne peut figurer dans mon EXECUTE, je tourne en rond...

Je vais essayé de trouvé une solution pour contourner les problèmes rencontrés avec ma solution de contour

Outils puissant mais avec quelques limites déplaisantes
@n@kin.be est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/06/2006, 11h56   #5
Membre chevronné
 
Avatar de Spoutnik
 
Homme
Inscription : octobre 2003
Messages : 668
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 32
Localisation : Etats-Unis

Informations forums :
Inscription : octobre 2003
Messages : 668
Points : 746
Points : 746
Hello,

pourquoi un EXECUTE?
un simple :
Code :
1
2
3
4
5
6
7
 
DECLARE
    member_info RECORD;
BEGIN
    SELECT INTO member_info * FROM t_tmp_member;
....
END;
ca marche pas?
__________________
Two beer or not two beer. (Shakesbeer)
Question technique par MP => poubelle!
Spoutnik est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/06/2006, 15h32   #6
Invité de passage
 
Inscription : juin 2006
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2006
Messages : 8
Points : 0
Points : 0
Si Spoutnik, cela fonctionne, mais comme je l'ai indiqué juste ici plus haut, cela ne fonctionne qu'une seule fois. Une fois la fonction exécutée, je dois la supprimer (drop) et la recréer pour que cela fonctionne à nouveau.

Voici ce que j'ai trouvé dans les FAQ sur postgresql.org:
Citation:
PL/PgSQL caches function scripts, and an unfortunate side effect is that if a PL/PgSQL function accesses a temporary table, and that table is later dropped and recreated, and the function called again, the function will fail because the cached function contents still point to the old temporary table. The solution is to use EXECUTE for temporary table access in PL/PgSQL. This will cause the query to be reparsed every time.
J'ai 5 instructions dans ma fonction: create temp table, insert, update, select into et le drop de ma table. Pour suivre les conseils de la FAQ, j'ai donc fais des EXECUTE mais seul le "select into" pose problème.
@n@kin.be est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/06/2006, 15h52   #7
Membre chevronné
 
Avatar de gerald2545
 
Inscription : février 2003
Messages : 643
Détails du profil
Informations forums :
Inscription : février 2003
Messages : 643
Points : 660
Points : 660
et es-tu obligé de travailler sur une table temporaire?
gerald2545 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/06/2006, 15h57   #8
Membre chevronné
 
Avatar de Spoutnik
 
Homme
Inscription : octobre 2003
Messages : 668
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 32
Localisation : Etats-Unis

Informations forums :
Inscription : octobre 2003
Messages : 668
Points : 746
Points : 746
Citation:
et es-tu obligé de travailler sur une table temporaire?
oui, c'est ca que je comprend pas non plus ....

@n@kin.be, tu pourrais mettre le code de ta fonction qu'on comprenne à quoi sert la table temporaire?
__________________
Two beer or not two beer. (Shakesbeer)
Question technique par MP => poubelle!
Spoutnik est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/06/2006, 16h22   #9
Invité de passage
 
Inscription : juin 2006
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2006
Messages : 8
Points : 0
Points : 0
Non, je ne suis pas obligé de travailler sur une table temporaire mais que cela soit une table temporaire ou non, le résultat est le même.

Voici la première version (sans EXECUTE):

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
 
CREATE OR REPLACE FUNCTION f_member_info(int4) RETURNS typ_member_alldetails AS
 
$BODY$
DECLARE member_info typ_member_alldetails;
 
BEGIN
 
CREATE TABLE t_tmp_member(
    card_id int4,
    member_type char(2),
    name char(30),
    firstname char(30),
    street char(50),
    street_nb char(5),
    zip char(5),
    city char(50),
    phone char(15),
    gsm char(15),
    email char(50),
    -- EF info
    section char(1),
    office char(10),
    offphone char(15),
    title char(3),
    off_nb char(10),
    -- AD info
    civ_status char(1),
    cat_desc char(30),
    sponsor_id int4,
    -- AG info
    sponsor_1_id int4,
    sponsor_2_id int4);
 
INSERT INTO t_tmp_member
SELECT *
FROM v_members_details
WHERE v_members_details.card_id = $1;
 
UPDATE t_tmp_member
SET component = (SELECT component FROM v_ef_details WHERE card_id = $1),
    section = (SELECT section FROM v_ef_details WHERE card_id = $1),
    office = (SELECT office FROM v_ef_details WHERE card_id = $1),
    offphone = (SELECT offphone FROM v_ef_details WHERE card_id = $1),
    title = (SELECT title FROM v_ef_details WHERE card_id = $1),
    off_nb = (SELECT off_nb FROM v_ef_details WHERE card_id = $1),
    civ_status = (SELECT civ_status FROM v_ad_details WHERE card_id = $1),
    cat_desc = (SELECT cat_desc FROM v_ad_details WHERE card_id = $1),
    sponsor_id = (SELECT sponsor_id FROM v_ad_details WHERE card_id = $1),
    sponsor_1_id = (SELECT sponsor_1_id FROM v_ag_details WHERE card_id = $1),
    sponsor_2_id = (SELECT sponsor_2_id FROM v_ag_details WHERE card_id = $1)
WHERE card_id = $1;
 
SELECT * FROM t_tmp_member INTO member_info;
 
DROP TABLE t_tmp_member;
 
RETURN member_info;
 
END;
 
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
A la première exécution de
Code :
SELECT * FROM f_member_info(1)
il me retourne un résultat correcte mais ensuite, il me retourne ceci:
Code :
1
2
3
4
 
ERROR:  relation WITH OID 18178 does NOT exist
CONTEXT:  SQL statement "INSERT INTO t_tmp_member SELECT * FROM v_members_details WHERE v_members_details.card_id =  $1 "
PL/pgSQL FUNCTION "f_member_info" line 36 at SQL statement
Voilà, j'espère que ces informations vont vous aider à y voir plus clair et d'hors et déjà, je vous remercie de l'intérêt que vous portez à mon petit problème.
@n@kin.be est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/06/2006, 16h34   #10
Membre chevronné
 
Avatar de gerald2545
 
Inscription : février 2003
Messages : 643
Détails du profil
Informations forums :
Inscription : février 2003
Messages : 643
Points : 660
Points : 660
en regardant viteuf, tu fais
Code :
SET component = (SELECT component FROM v_ef_details WHERE card_id = $1),
mais le champs component n'existe pas dans ta table temporaire...je regarde plus en détail
gerald2545 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/06/2006, 16h41   #11
Membre chevronné
 
Avatar de gerald2545
 
Inscription : février 2003
Messages : 643
Détails du profil
Informations forums :
Inscription : février 2003
Messages : 643
Points : 660
Points : 660
je suis peut-être à côté de la plaque, mais pourquoi est-ce que tu ne fais pas des jointures plutôt que de travailler sur une table temporaire que tu mets à jour selon ce même principe?
gerald2545 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/06/2006, 17h03   #12
Membre chevronné
 
Avatar de Spoutnik
 
Homme
Inscription : octobre 2003
Messages : 668
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 32
Localisation : Etats-Unis

Informations forums :
Inscription : octobre 2003
Messages : 668
Points : 746
Points : 746
Ok, je comprend un peu mieux.
Déjà, ce que tu utilise n'est pas une table temporaire au sens SQL (qu'on me corrige si je me trompe surtout!).
Tu as un mot clef (TEMP / TEMPORARY) à utiliser pour que ta table soit droppée automatiquement à la fin de la session.

La séquence CREATE table + insert pourrait peut déjà être remplacée par
Code :
SELECT INTO TEMP t_tmp_member
ou bien par l'utilisation d'un type record.

"member_info" sert à quoi?

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
 
CREATE OR REPLACE FUNCTION f_member_info(int4) RETURNS typ_member_alldetails AS
 
$BODY$
DECLARE 
t_tmp_member RECORD;
BEGIN
 
SELECT 
members.card_id ,
members.member_type ,
members.name ,
members. firstname ,
members.street ,
members.street_nb ,
members.zip ,
members.city ,
members.phone ,
members.gsm ,
members.email ,
    -- EF info
    offi.section, 
    offi.office ,
    offi.offphone ,
    offi.title ,
    offi.off_nb ,
    -- AD info,
    offi.civ_status ,
    offi.cat_desc ,
    offi.sponsor_id ,
    -- AG info
    offi.sponsor_1_id ,
    offi.sponsor_2_id );
 INTO t_tmp_member
FROM v_members_details members JOIN office offi ON (members.card_id = offi.card_id)
WHERE members.card_id = $1;
 
 
RETURN t_tmp_member;
 
END;
 
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
Je ne suis pas qur que ca plante pas à la compilation, à cause du possible retour de plusieurs lignes.

A mois que tu ai un besoin précis de redéfinir les types de tes colonnes ( de t_tmp_member , ca sert à rien de le faire.



+1 pour le 'component' qui existe pas, j'avais po vu
__________________
Two beer or not two beer. (Shakesbeer)
Question technique par MP => poubelle!
Spoutnik est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/06/2006, 17h22   #13
Membre chevronné
 
Avatar de gerald2545
 
Inscription : février 2003
Messages : 643
Détails du profil
Informations forums :
Inscription : février 2003
Messages : 643
Points : 660
Points : 660
c'était en effet l'idée que je me faisais de la solution, sauf que tu as fait un petit mic mac dans les tables/vues
la requête devant être (je crois) :
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
SELECT 
members.card_id ,
members.member_type ,
members.name ,
members. firstname ,
members.street ,
members.street_nb ,
members.zip ,
members.city ,
members.phone ,
members.gsm ,
members.email ,
    -- EF info
    ef.section, 
    ef.office ,
    ef.offphone ,
    ef.title ,
    ef.off_nb ,
    -- AD info,
    ad.civ_status ,
    ad.cat_desc ,
    ad.sponsor_id ,
    -- AG info
    ag.sponsor_1_id ,
    ag.sponsor_2_id );
 INTO t_tmp_member
FROM members 
JOIN v_ef_details ef ON (members.card_id = ef.card_id)
JOIN v_ad_details ad ON (members.card_id = ad.card_id)
JOIN v_ag_details ag ON (members.card_id = ag.card_id)
WHERE members.card_id = $1;
gerald2545 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/06/2006, 17h28   #14
Membre chevronné
 
Avatar de Spoutnik
 
Homme
Inscription : octobre 2003
Messages : 668
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 32
Localisation : Etats-Unis

Informations forums :
Inscription : octobre 2003
Messages : 668
Points : 746
Points : 746
j'ai lu trop vite les noms.
__________________
Two beer or not two beer. (Shakesbeer)
Question technique par MP => poubelle!
Spoutnik est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/06/2006, 17h41   #15
Membre chevronné
 
Avatar de gerald2545
 
Inscription : février 2003
Messages : 643
Détails du profil
Informations forums :
Inscription : février 2003
Messages : 643
Points : 660
Points : 660
pas grave d'ailleurs moi aussi je me suis planté dans les joins, j'ai mis le même alias pour les trois, je viens de corriger
gerald2545 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/06/2006, 10h08   #16
Invité de passage
 
Inscription : juin 2006
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2006
Messages : 8
Points : 0
Points : 0
Par défaut ben non...

Merci encore à Gerald et à Spoutnik pour leur intérêt à résoudre mon problème.

L'idée est bonne est les "JOIN" mais cela ne peut fonctionner car un membre est soit EF (effectif), AD (adhérent) ou AG (agréé). Si j'écris ma fonction avec les joins pour membres, ef, ad et ag, la requête ne me retourne rien.

C'est la raison pour laquelle j'avais pensé à un insert suivit d'un update (pour le component, c'est juste une erreur de copier/coller ) puisque comme je vous l'ai dit, ma fonction fonctionne 1 fois.

Au départ, ce que j'avais fais était plus simple
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
 
CREATE OR REPLACE FUNCTION f_member_info(int4)
  RETURNS ??? AS
$BODY$
 
DECLARE memtype char(2);
 
BEGIN
 
SELECT member_type FROM t_members WHERE card_id=$1 INTO memtype;
 
IF memtype = 'EF' THEN
     SELECT m.*, ef.*
     FROM v_members_details m, v_ef_details ef
     WHERE m.card_id=ef.card_id
     AND m.card_id=$1;
ELSIF memtype = 'AD' THEN
     SELECT m.*, ad.*
     FROM v_members_details m, v_ad_details ef
     WHERE m.card_id=ad.card_id
     AND m.card_id=$1;
ELSE
     SELECT m.*, ag.*
     FROM v_members_details m, v_ag_details ef
     WHERE m.card_id=ag.card_id
     AND m.card_id=$1;
END IF;
 
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
J'avais écris ça à sauce "MS SQL Server", SGDB sur lequel j'avais suivi toutes mes formations mais mon problème avec PostGreSQL c'est le type de retour à spécifier car mes trois SELECT ne me retourne pas la même chose.

On est lundi, on est motivé alors on va continuer à chercher
Une solution par le front-end reste possible mais je préfère éviter, j'utiliserai cette solution en dernier recourd.
@n@kin.be est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/06/2006, 10h55   #17
Membre chevronné
 
Avatar de Spoutnik
 
Homme
Inscription : octobre 2003
Messages : 668
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 32
Localisation : Etats-Unis

Informations forums :
Inscription : octobre 2003
Messages : 668
Points : 746
Points : 746
Hello,

regarde du coté des anyelement

+SET OF si tu as plusieurs lignes à renvoyer.
__________________
Two beer or not two beer. (Shakesbeer)
Question technique par MP => poubelle!
Spoutnik est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/06/2006, 11h07   #18
Invité de passage
 
Inscription : juin 2006
Messages : 8
Détails du profil
Informations forums :
Inscription : juin 2006
Messages : 8
Points : 0
Points : 0
Par défaut Resolu

Ok Spoutnik, je jetterai un oeil sur les types polymorphiques!

Mais en attendant, en postant ma dernière réponse, une idée m'a traversé l'esprit (ça fait mal!) et j'ai alors décidé de combiné ma première solution avec vos idées (merci encore).
Voici en gros ce que cela donne:
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
 
CREATE OR REPLACE FUNCTION f_select_member_details(int4)
  RETURNS typ_member_alldetails AS
$BODY$
 
DECLARE 
	memtype char(2);
	myrec typ_member_alldetails;
 
BEGIN
 
SELECT member_type FROM t_members WHERE card_id=$1 INTO memtype;
 
IF memtype = 'EF' THEN
	SELECT	members.card_id,
		members.member_type,
		members.name,
		members. ... (tous les champs de members),
		members.fct_code,
		ef. ... (tous les champs de la VIEW EF),
	INTO myrec
	FROM v_members_details members
	JOIN v_ef_details ef ON (members.card_id = ef.card_id)
	WHERE members.card_id = $1;
ELSIF memtype = 'AD' THEN
	SELECT	members.card_id,
		members.member_type,
		members.name,
		members. ... (tous les champs de members),
		members.fct_code,
                          NULL,
                          NULL,
                          NULL,
                          NULL,
                          NULL,
                          NULL, (autant de NULL que de champs dans la VIEW EF)
		ad. ... (tous les champs de la VIEW AD),
	INTO myrec
	FROM v_members_details members
	JOIN v_ad_details ef ON (members.card_id = ad.card_id)
	WHERE members.card_id = $1;
ELSE
	SELECT	members.card_id,
		members.member_type,
		members.name,
		members. ... (tous les champs de members),
		members.fct_code,
                          NULL,
                          NULL,
                          NULL,
                          NULL,
                          NULL,
                          NULL, 
                          NULL,
                          NULL,
                          NULL, (autant de NULL que de champs dans les VIEW EF et AD)
		ag. ... (tous les champs de la VIEW AG),
	INTO myrec
	FROM v_members_details members
	JOIN v_ag_details ef ON (members.card_id = ag.card_id)
	WHERE members.card_id = $1;
END IF;
 
RETURN myrec;
 
END;
 
$BODY$
  LANGUAGE 'plpgsql' VOLATILE;
Merci pour votre aide qui a été pour moi un source d'inspiration.
@n@kin.be 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 12h58.


 
 
 
 
Partenaires

Hébergement Web