Vous n'êtes pas identifié(e).
Bonjour à tous,
Dans certaines requêtes MSSQL, nous avons utilisé des tables temporaires pour faire des traitements spécifiques. Par exemple :
DECLARE @Cas TABLE
(intCasId INT,
strNoDossier VARCHAR(50),
strConseillerNom VARCHAR(255),
intLocalisationId INT,
strLocalisationNom VARCHAR(255),
intRegionId INT,
strRegionNom VARCHAR(255),
strActiviteNom VARCHAR(100),
intTemps INT,
intCouts INT,
strDossierEtatNom VARCHAR(255)
)
INSERT INTO @Cas(intCasId, strNoDossier, strConseillerNom, intLocalisationId, strLocalisationNom, intRegionId, strRegionNom, strActiviteNom, intTemps, intCouts, strDossierEtatNom)
[...] une requête SELECT qui alimente l'instruction INSERT ci-dessus
Plusieurs autres traitements suivent, et à la fin je fais SELECT * FROM @Cas, et c'est le "resultset" qui est envoyé à mon rapport (JasperSoft iReport).
J'aimerais reproduire la même chose en PostgreSQL. J'ai lu sur les tables temporaires, mais j'aimerais savoir si c'est possible de déclarer une table "virtuelle" pour l'exécution de la fonction seulement?
Merci beaucoup
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne
Les tables temporaires sont automatiquement détruites à la fin de la session. Cependant, elles peuvent aussi l'être au COMMIT avec l'option "ON COMMIT DROP". Donc ça change un peu de MSSQL car vous ne pouvez pas faire le DECLARE. Vous devez passer par un CREATE TEMPORARY TABLE... ON COMMIT DROP. Quant au INSERT, ça se passe comme pour tout autre INSERT : INSERT INTO Cas(....) VALUES (...).
Guillaume.
Hors ligne
D'accord. J'ai fait plusieurs tests ce matin avec cette commande mais lorsque j'arrivais au INSERT, PostgreSQL me disait que le nom de ma table temporaire n'existait pas (relation does not exist).
Faut-il mettre un prefix comme $ pour les paramètres?
Merci !
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne
Voici le code de la fonction:
PREPARE t_cas AS
SELECT Cas.intCasId,
Cas.strNoDossier,
Users.strUserFirstName || ' ' || Users.strUserLastName AS strConseillerNom,
Localisation.intLocalisationId,
CASE $5
WHEN 'fr' THEN Localisation.strLocalisationNomFr
WHEN 'en' THEN Localisation.strLocalisationNomEn
END AS strLocalisationNom,
Region.intRegionId,
CASE $5
WHEN 'fr' THEN Region.strRegionNomFr
WHEN 'en' THEN Region.strRegionNomEn
END AS strRegionNom,
CASE $5
WHEN 'fr' THEN ActiviteNom.strActiviteNomFr
WHEN 'en' THEN ActiviteNom.strActiviteNomEn
END AS strActiviteNom,
Cheminement.intTemps,
Cheminement.intCouts,
CASE $5
WHEN 'fr' THEN DossierEtat.strDossierEtatAbrFr
WHEN 'en' THEN DossierEtat.strDossierEtatAbrEn
END AS strDossierEtatNom
FROM stirq.Cas
INNER JOIN stirq.DossierEtat ON
stirq.Cas.intDossierEtatId = stirq.DossierEtat.intDossierEtatId
INNER JOIN stirq.Localisation ON
stirq.Cas.intLocalisationId = stirq.Localisation.intLocalisationId
INNER JOIN stirq.Region ON
stirq.Localisation.intRegionId = stirq.Region.intRegionId
INNER JOIN stirq.Intervention ON
stirq.Cas.intCasId = stirq.Intervention.intCasId
INNER JOIN stirq.ActiviteNom ON
stirq.Intervention.intActiviteNomId = stirq.ActiviteNom.intActiviteNomId
INNER JOIN stirq.Cheminement ON
stirq.Intervention.intInterventionId = stirq.Cheminement.intInterventionId
WHERE
Cheminement.datCheminement BETWEEN $3 AND $4 AND
Region.intRegionId = $1
ORDER BY Cas.strNoDossier, ActiviteNom.intOrder;
CREATE TEMP TABLE t_cas WITH (OIDS) ON COMMIT DROP AS
EXECUTE t_cas;
INSERT INTO t_cas
SELECT 0,
NULL,
NULL,
0,
NULL,
$1,
$2,
CASE $5
WHEN 'fr' THEN stirq.ActiviteNom.strActiviteNomFr
WHEN 'en' THEN stirq.ActiviteNom.strActiviteNomEn
END AS strActiviteNom,
NULL,
NULL,
NULL
FROM stirq.ActiviteNom
WHERE intActiviteTypeId = 4;
SELECT * FROM t_cas;
J'ai le message suivant :
ERROR: relation "t_cas" does not exist
LINE 156: INSERT INTO t_cas(intCasId, strNoDossier, strConseillerNom,...
J'ai suivi les instructions à la page 917 dans le manuel de PostgreSQL 9.0.3 (CREATE TABLE AS)
Merci!
Dernière modification par charleydc5 (18/08/2011 14:15:20)
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne
Pas d'erreur à l'exécution du PREPARE et du CREATE TEMP TABLE ? et qu'y a-t-il dans le [...] ?
Guillaume.
Hors ligne
Non, la seule erreur que le compilateur me donne est le t_cas does not exist.
En fait, l'instruction INSERT suit immédiatement le EXECUTE. Les [...] sont inutiles... désolé
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne
J'ai ajouté le détail de mon INSERT dans le post #4.
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne
Ah, je crois avoir compris. Vous n'êtes pas dans une transaction. Du coup, la fin du CREATE TEMP TABLE supprime la table, ce qui fait que le INSERT est en erreur. Me trompe-je?
Guillaume.
Hors ligne
Ce serait effectivement très logique! Par contre, j'avais essayé d'enlever ON COMMIT DROP et de faire le drop moi-même à la fin de la fonction... même résultat.
L'instruction CREATE était ainsi :
CREATE TEMP TABLE t_cas WITH (OIDS) AS
EXECUTE t_cas;
.. suivi de l'instruction INSERT
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne
Étonnant, je n'ai aucun problème avec ça. Voici mon test:
b1=# create or replace function titi() returns text language plpgsql
as $$
declare
tmp text;
begin
prepare toto as select current_query from pg_stat_activity;
create temp table toto on commit drop as execute toto;
select into tmp * from toto limit 1;
deallocate toto;
return tmp;
end
$$;
CREATE FUNCTION
b1=# select titi();
titi
----------------
select titi();
(1 row)
b1=# select titi();
titi
----------------
select titi();
(1 row)
b1=# select titi();
titi
----------------
select titi();
(1 row)
b1=# select * from toto;
ERREUR: la relation « toto » n'existe pas
LINE 1: select * from toto;
^
b1=# select titi(), 2;
titi | ?column?
-------------------+----------
select titi(), 2; | 2
(1 row)
b1=# select titi(), true;
titi | bool
----------------------+------
select titi(), true; | t
(1 row)
Guillaume.
Hors ligne
Même si je ne pense pas que ce soit le problème, il y a un soucis dans le INSERT : il y a un point-virgule après un NULL.
Guillaume.
Hors ligne
J'ai enlevé le point virgule et c'est la même chose.
Est-ce que ça pourrait avoir un lien avec mon schéma?
J'ai toutefois tenté de spécifier stirq. avant t_cas et j'ai le même problème..
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne
Les tables temporaires sont des schémas à part, donc non, ça ne peut pas être le problème.
Guillaume.
Hors ligne
J'ai enlevé le point virgule et c'est la même chose.
Est-ce que ça pourrait avoir un lien avec mon schéma?
J'ai toutefois tenté de spécifier stirq. avant t_cas et j'ai le même problème..
C'est-à-dire que tu as une table stirq.t_cas qui existe et que INSERT INTO stirq.t_cas sort un message d'erreur disant qu'elle n'existe pas?
A ce niveau là on peut se demander si tu exécutes bien la version de la fonction que tu modifies.
Par exemple il pourrait y avoir une version dans le schéma public, une autre avec le même nom dans le schéma stirq.
Si à l'exécution il va chercher la fonction dans l'autre schéma, ça expliquerait que quoi que tu essaies ça ne change rien à l'erreur (qui n'a pas lieu d'être).
Il serait intéressant de vérifier que ton CREATE FUNCTION spécifie ou non un schéma, quel est le search_path au moment du CREATE FUNCTION, et est-ce que c'est le même search_path qu'au moment de l'exécution de la fonction, et enfin est-ce qu'il y a plusieurs instances de la fonction créées dans des schémas différents.
@DanielVerite
http://blog-postgresql.verite.pro/
Hors ligne
La fonction n'est même pas encore créée, je ne réussi pas à la faire compiler.
Voici le code d'entête de ma fonction :
CREATE OR REPLACE FUNCTION stirq.qryCasTempsCoutsTypeRpt(
pvintRegionId INT,
pvstrRegionNom VARCHAR(100),
pvdatFrom TIMESTAMP,
pvdatTo TIMESTAMP,
pvstrLangue VARCHAR(10)
)
RETURNS TABLE(
intCasId INT,
strNoDossier VARCHAR(50),
strConseillerNom VARCHAR(255),
intLocalisationId INT,
strLocalisationNom VARCHAR(255),
intRegionId INT,
strRegionNom VARCHAR(255),
strActiviteNom VARCHAR(100),
intTemps INT,
intCouts INT,
strDossierEtatNom VARCHAR(255)
) AS
$BODY$
[...]
Je n'ai qu'un seul schéma dans cette base de données, et il est nommé "stirq". J'ai supprimé le schéma public.
Si je roule SHOW search_path, j'ai le résultat ""$user",public"
Merci
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne
La fonction n'est même pas encore créée, je ne réussi pas à la faire compiler.
Je pensais que c'était une erreur d'exécution parce que le message d'erreur initial, celui-ci:
ERROR: relation "t_cas" does not exist
LINE 156: INSERT INTO t_cas(intCasId, strNoDossier, strConseillerNom,...
est visiblement une erreur d'exécution, pas une erreur de création de fonction.
Est-ce que tu pourrais copier-coller dans la discussion l'intégralité du create function dans sa version actuelle, message d'erreur inclus?
@DanielVerite
http://blog-postgresql.verite.pro/
Hors ligne
Merci de présenter la fonction entière ainsi que le message d'erreur exact.
Guillaume.
Hors ligne
Je pense que j'ai mis le doigt sur le problème, mais je ne comprend pas pourquoi PostgreSQL agit ainsi.
J'ai testé le code suivant dans pgAdmin :
CREATE TEMP TABLE temptest(col INTEGER);
INSERT INTO temptest VALUES (1);
INSERT INTO temptest VALUES (2);
INSERT INTO temptest VALUES (3);
SELECT * FROM temptest;
En appuyant sur Execute Query, je vois le résultat de la requête, donc :
1
2
3
Si je réappuie sur Execute Query, j'ai le message suivant comme mon problème initial:
ERROR: relation "temptest" already exists
********** Error **********
ERROR: relation "temptest" already exists
SQL state: 42P07
Vraiment bizzare... quelqu'un a une idée??
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne
Voici la fonction au complet :
CREATE OR REPLACE FUNCTION stirq.qryCasTempsCoutsTypeRpt(
pvintRegionId INT,
pvstrRegionNom VARCHAR(100),
pvdatFrom TIMESTAMP,
pvdatTo TIMESTAMP,
pvstrLangue VARCHAR(10)
)
RETURNS TABLE(
intCasId INT,
strNoDossier VARCHAR(50),
strConseillerNom VARCHAR(255),
intLocalisationId INT,
strLocalisationNom VARCHAR(255),
intRegionId INT,
strRegionNom VARCHAR(255),
strActiviteNom VARCHAR(100),
intTemps INT,
intCouts INT,
strDossierEtatNom VARCHAR(255)
) AS
$BODY$
PREPARE t_cas AS
SELECT Cas.intCasId AS intCasIdGlobal,
Cas.strNoDossier,
Users.strUserFirstName || ' ' || Users.strUserLastName AS strConseillerNom,
Localisation.intLocalisationId,
CASE $5
WHEN 'fr' THEN Localisation.strLocalisationNomFr
WHEN 'en' THEN Localisation.strLocalisationNomEn
END AS strLocalisationNom,
Region.intRegionId,
CASE $5
WHEN 'fr' THEN Region.strRegionNomFr
WHEN 'en' THEN Region.strRegionNomEn
END AS strRegionNom,
CASE $5
WHEN 'fr' THEN ActiviteNom.strActiviteNomFr
WHEN 'en' THEN ActiviteNom.strActiviteNomEn
END AS strActiviteNom,
Cheminement.intTemps,
Cheminement.intCouts,
CASE $5
WHEN 'fr' THEN DossierEtat.strDossierEtatAbrFr
WHEN 'en' THEN DossierEtat.strDossierEtatAbrEn
END AS strDossierEtatNom
FROM stirq.Cas
INNER JOIN stirq.DossierEtat ON
stirq.Cas.intDossierEtatId = stirq.DossierEtat.intDossierEtatId
INNER JOIN stirq.Localisation ON
stirq.Cas.intLocalisationId = stirq.Localisation.intLocalisationId
INNER JOIN stirq.Region ON
stirq.Localisation.intRegionId = stirq.Region.intRegionId
INNER JOIN stirq.Intervention ON
stirq.Cas.intCasId = stirq.Intervention.intCasId
INNER JOIN stirq.ActiviteNom ON
stirq.Intervention.intActiviteNomId = stirq.ActiviteNom.intActiviteNomId
INNER JOIN stirq.Cheminement ON
stirq.Intervention.intInterventionId = stirq.Cheminement.intInterventionId
INNER JOIN
(SELECT stirq.Cas.intCasId,
MAX(intCheminementId) AS intLastCheminementId
FROM stirq.Cheminement
INNER JOIN stirq.Intervention ON
stirq.Cheminement.intInterventionId = stirq.Intervention.intInterventionId
INNER JOIN stirq.Cas ON
stirq.Intervention.intCasId = stirq.Cas.intCasId
INNER JOIN stirq.Localisation ON
stirq.Cas.intLocalisationId = stirq.Localisation.intLocalisationId
INNER JOIN stirq.Region ON
stirq.Localisation.intRegionId = stirq.Region.intRegionId
WHERE
stirq.Cheminement.datCheminement BETWEEN $3 AND $4 AND
Region.intRegionId = $1
GROUP BY Cas.intCasId
) AS vwsLastCheminementCas ON
Cas.intCasId = vwsLastCheminementCas.intCasId
INNER JOIN (
SELECT Cheminement.intCheminementId,
Cheminement.intConseiller1Id
FROM stirq.Cheminement
INNER JOIN stirq.Intervention ON
stirq.Cheminement.intInterventionId = stirq.Intervention.intInterventionId
INNER JOIN stirq.Cas ON
stirq.Intervention.intCasId = stirq.Cas.intCasId
INNER JOIN stirq.Localisation ON
stirq.Cas.intLocalisationId = stirq.Localisation.intLocalisationId
INNER JOIN stirq.Region ON
stirq.Localisation.intRegionId = stirq.Region.intRegionId
WHERE
stirq.Cheminement.datCheminement BETWEEN $3 AND $4 AND
stirq.Region.intRegionId = $1
) AS vwsLastConseillerCas ON
vwsLastCheminementCas.intLastCheminementId = vwsLastConseillerCas.intCheminementId
INNER JOIN stirq.Users ON
vwsLastConseillerCas.intConseiller1Id = stirq.Users.intUserId
WHERE
Cheminement.datCheminement BETWEEN $3 AND $4 AND
Region.intRegionId = $1
ORDER BY Cas.strNoDossier, ActiviteNom.intOrder;
CREATE TEMP TABLE t_cas AS EXECUTE t_cas;
INSERT INTO t_cas
SELECT 0,
NULL,
NULL,
0,
NULL,
$1,
$2,
CASE $5
WHEN 'fr' THEN stirq.ActiviteNom.strActiviteNomFr
WHEN 'en' THEN stirq.ActiviteNom.strActiviteNomEn
END AS strActiviteNom,
NULL,
NULL,
NULL
FROM stirq.ActiviteNom
WHERE intActiviteTypeId = 4;
SELECT * FROM t_cas;
$BODY$
LANGUAGE sql VOLATILE
COST 100;
Message d'erreur :
ERROR: relation "t_cas" does not exist
LINE 140: INSERT INTO t_cas
^
********** Error **********
ERROR: relation "t_cas" does not exist
SQL state: 42P01
Character: 3683
Dernière modification par charleydc5 (18/08/2011 16:45:24)
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne
Pas bizarre du tout. La table temporaire existe tout le temps de la session (donc tant qu'il n'y a pas déconnexion de l'éditeur de requête dans votre cas).
Guillaume.
Hors ligne
Pas bizarre du tout. La table temporaire existe tout le temps de la session (donc tant qu'il n'y a pas déconnexion de l'éditeur de requête dans votre cas).
Je comprend, mais je ne me suis pas déconnecté?! Normalement elle aurait dûe exister encore puisque je n'ai pas fermer l'éditeur de requête, non? Le message que j'ai est comme si la table n'existait pas, alors qu'elle devrait logiquement exister encore si on prend en considération vos explications antérieures.
Merci beaucoup
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne
Ah! C'est pas LANGUAGE sql qu'il faut pour la fonction , c'est plpgsql.
@DanielVerite
http://blog-postgresql.verite.pro/
Hors ligne
Ah! C'est pas LANGUAGE sql qu'il faut pour la fonction , c'est plpgsql.
Exactement!! J'ai changé le language et ajouté les BEGIN et END; et tout fonctionne à merveille...
Désolé les gars, c'était mon erreur.
Merci beaucoup pour votre support. C'est grandement apprécié.
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne
Normalement elle aurait dûe exister encore puisque je n'ai pas fermer l'éditeur de requête, non?
Hmmm, lisez le message d'erreur de pgAdmin : ERROR: relation "temptest" already exists. Il indique bien que la relation temptest existe déjà.
Et pour la fonction, dverite a raison. Vous voulez plpgsql et non pas sql.
Guillaume.
Hors ligne
Encore une fois j'avais lu trop vite!
Discussion close!
Charles Morin
PostgreSQL 9.0.3 sur Windows 2008 Server Standard (x64)
Hors ligne