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

PostgreSQL Discussion :

table temporaire dans une fonction


Sujet :

PostgreSQL

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 19
    Points : 17
    Points
    17
    Par défaut table temporaire dans une fonction
    Bonjour,

    J'ai créé une table temporaire dans une procédure dans laquelle je stocke les résultats d'un calcul.

    A la fin de la procédure, je renvoie les lignes de cette table temporaire comme résultat de la fonction.

    Cela marche très bien lors du premier appel de la fonction. mais lors du 2ème appel, il me met le message d'erreur suivant : ERROR: relation with OID 25509 does not exist

    En fait, je crois qu'il garde en mémoire l'OID de la table créée lors du 1er appel de la proc. Mais comme la table est détruite sur le commit, elle doit être recréée avec un autre OID : d'où mon problème.


    Merci de votre aide ...

  2. #2
    Membre émérite
    Avatar de hpalpha
    Inscrit en
    Mars 2002
    Messages
    769
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 769
    Points : 2 545
    Points
    2 545
    Par défaut
    bonjour,

    peux tu mettre ta fonction stp ?
    Delphi 2009 - ZeosLib - DevExpress - TMS - PgDAC
    PostgreSQL 8.4 sous Debian
    Sites : http://postgresql.developpez.com http://dgriessinger.developpez.com

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 19
    Points : 17
    Points
    17
    Par défaut
    voici la fonction.
    Je l'ai plus utilisée pour apprendre à maîtriser les tables temporaires dans les procs stockées car on pourrait faire la même chose avec une focntion SQL qui renverrait un select ... limit X ...

    A priori, mon problème viendrait du fait suivant : "PL/PgSQL met en cache les fonctions. Un effet de bord malencontrueux est que, si une fonction PL/pgsql accède à une table temporaire et que cette table est ensuite supprimée et recréée, un prochain appel à la fonction échouera car le contenu de la fonction en cache pointera toujours vers l'ancienne table temporaire".
    Comment faire pour éviter ce problème ?

    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
     
    --objectif : renvoyer les x plus grosses commandes d'un client
    CREATE OR REPLACE FUNCTION ca_cl2(no_cl char(5), nb integer)
      RETURNS setof v_cde_total AS
    $$	
    DECLARE
     cdes v_cde_total%rowtype; --crée  un curseur qui a la même structure que la vue v_cde_total
     n bigint;
     i int;
     
    BEGIN
    i:=0;
    n:=3;
      -- crée une table temporaire qui sera détruite au moment du commit
    create temporary table temp_v_cde on commit drop  as 
    	SELECT code_client, societe ,  n_commande ,date_commande , total from v_cde_total where code_client = no_cl;
     
    create temporary table temp_v_cde_resu 
    	(code_client varchar(5), societe varchar(40),  n_commande integer,date_commande date, total numeric) 
    	on commit drop ;
     
    --recopie toutes les commandes du client dans temp_v_cde 
    select count(*) into n from temp_v_cde ;
     
     
    while (i<nb and i<n) loop
    	--trouve la plus grosse commande et la transfère dans la table resu (et la supprime de la table temp)
    	insert into temp_v_cde_resu select * from temp_v_cde where total = (select max (total) from temp_v_cde);
    	delete from temp_v_cde where total = (select max (total) from temp_v_cde);
    	i:= i+1;
    end loop;
    	for cdes in SELECT * from temp_v_cde_resu LOOP
    		RETURN NEXT cdes ;
    	END LOOP ;
    end;
    $$
      LANGUAGE 'plpgsql' volatile;

  4. #4
    Membre émérite
    Avatar de hpalpha
    Inscrit en
    Mars 2002
    Messages
    769
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 769
    Points : 2 545
    Points
    2 545
    Par défaut
    normalement il ne devrait pas mettre en cache, ta fonction est VOLATILE
    Delphi 2009 - ZeosLib - DevExpress - TMS - PgDAC
    PostgreSQL 8.4 sous Debian
    Sites : http://postgresql.developpez.com http://dgriessinger.developpez.com

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 19
    Points : 17
    Points
    17
    Par défaut
    Le problème venait effectivement du fait que pg met en cache les fonctions : si une fonction PL/pgsql accède à une table temporaire et que cette table est ensuite supprimée et recréée, un prochain appel à la fonction échouera car le contenu de la fonction en cache pointera toujours vers l'ancienne table temporaire

    même si la fonction est VOLATILE, le problème existe pour les tables temporaires.

    La solution consiste à utiliser EXECUTE.
    cf code commenté ci-dessous

    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
     
    CREATE OR REPLACE FUNCTION ca_cl2(no_cl char(5), nb integer)
      RETURNS setof v_cde_total AS
    $$	
    DECLARE
     cdes v_cde_total%rowtype; --crée  un curseur qui a la même structure que la vue v_cde_total
     n bigint;
     i int;
    request1 varchar(200);
    request2 varchar(200);
    request3 varchar(200);
     
    BEGIN
    i:=0;
      -- crée une table temporaire qui sera détruite au moment du commit
    --table qui contient toutes les commandes du client
    create temporary table temp_v_cde on commit drop  as 
    	SELECT code_client, societe ,  n_commande ,date_commande , total from v_cde_total where code_client = no_cl;
     
    --table de résultat qui contiendra les x plus grosses commandes du client
    create temporary table temp_v_cde_resu 
    	(code_client varchar(5), societe varchar(40),  n_commande integer,date_commande date, total numeric) 
    	on commit drop ;
     
    --compte le nombre de commandes du client
    select count(*) into n  from v_cde_total where code_client = no_cl;
     
    --prend les x plus grosses commandes du client et les recopie dans la table temp_v_cde_resu
    while (i<nb and i<n) loop
    	/*trouve la plus grosse commande et la transfère dans la table resu (et la supprime de la table temp)
    	On est obligé de passer par une commande execute car "PL/PgSQL met en cache les fonctions. 
    	Un effet de bord malencontrueux est que, si une fonction PL/pgsql accède à une table temporaire et que cette table est 
    	ensuite supprimée et recréée, un prochain appel à la fonction échouera car le contenu de la fonction en cache pointera 
    	toujours vers l'ancienne table temporaire".*/
    	request1:= 'insert into temp_v_cde_resu select * from temp_v_cde where total = (select max (total) from temp_v_cde)';
    	request2:= 'delete from temp_v_cde where total = (select max (total) from temp_v_cde)';
    	execute request1;
    	execute request2;
     
    i:= i+1;
    end loop;
    	request3:='SELECT * from temp_v_cde_resu';
    	for cdes in execute request3 LOOP
    		RETURN NEXT cdes ;
    	END LOOP ;
    end;
    $$
      LANGUAGE 'plpgsql' volatile;

  6. #6
    Membre émérite
    Avatar de hpalpha
    Inscrit en
    Mars 2002
    Messages
    769
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 769
    Points : 2 545
    Points
    2 545
    Par défaut
    Oui effectivement, je connaissais pas ce comportement, j'ai vu sur techdev de pg, qu'il fallait utiliser un execute, etrange .... est ce que ce sera un jour corrigé ? je ne sais pas , Bruce Momjian connait ce bug depuis la 7.4
    Delphi 2009 - ZeosLib - DevExpress - TMS - PgDAC
    PostgreSQL 8.4 sous Debian
    Sites : http://postgresql.developpez.com http://dgriessinger.developpez.com

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    26
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 26
    Points : 25
    Points
    25
    Par défaut
    Je viens de tester sur la version 8.3 : le problème persiste

  8. #8
    Membre habitué

    Profil pro
    Inscrit en
    Mai 2002
    Messages
    116
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 116
    Points : 144
    Points
    144
    Par défaut
    merci pour le tuyo, je viens de rencontrer le même problème également. C'est quand même extraordinaire ...

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 14/09/2010, 11h58
  2. Recherche dans table MySQL dans une fonction js
    Par dodo91 dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 20/05/2009, 11h00
  3. Réponses: 3
    Dernier message: 10/07/2008, 20h26
  4. Impossible de créer une table temporaire dans une fonction
    Par bossun dans le forum MS SQL Server
    Réponses: 1
    Dernier message: 05/10/2007, 10h03
  5. Réponses: 8
    Dernier message: 06/06/2007, 17h03

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