PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 Re : PL/pgSQL » Inclure les lignes vides dans un SELECT... BETWEEN » 17/10/2016 14:59:47

Bonjour,
merci pour cette piste, mais je ne parviens pas à faire ma jointure correctement :
quel que soit le type de jointure, je n'arrive toujours à récupérer que les lignes
où le champ "valeurs" est non nul.
Pourriez-vous préciser votre idée ?

#2 PL/pgSQL » Inclure les lignes vides dans un SELECT... BETWEEN » 17/10/2016 11:30:42

XPBT
Réponses : 3

Bonjour,
j'aimerais créer une requête qui me renvoie également les lignes vides de ma table.
Je m'explique : imaginons une table à deux colonnes, mettons "jour" et "valeur",
pour laquelle, sur un intervalle de temps donné, certaines lignes sont vides (pas de valeur
ce jour-là). Si on fait :
       SELECT jour, valeur FROM table WHERE jour BETWEEN '2016-01-01' AND '2016-06-30'
la requête ne renverra que les lignes (c'est-à-dire les jours) où "valeur" a été renseignée.
Ce que je voudrais que la requête me renvoie, , c'est une liste de tous les jours compris
entre '2016-01-01' et '2016-06-30', avec la colonne "valeur" renseignée quand c'est possible
et "0" ou "NULL" quand il n'y a pas de valeur à cette date.
En gros il faudrait créer une itération entre les bornes du BETWEEN, ou créer une jointure
avec une table "calendrier" comprenant tous les jours (je ne peux pas créer une telle table,
j'envoie ma requête sur un serveur sur lequel je n'ai pas la main).
J'espère que mes explications sont claires, en tout cas merci d'avance pour vos idées.

#3 Général » Transfert de données d'une base distante à une base locale » 04/03/2015 17:19:49

XPBT
Réponses : 2

Bonjour,
je dois travailler sur des données stockées sur un serveur distant. Pour des raisons pratiques, je ne peux travailler directement dessus, et dois donc rapatrier les données du serveur sur une base locale. Existe-t-il un moyen plus simple que de passer par le format csv en faisant \copy (table distante) to (fichier local) puis copy (table locale) from (fichier local)? Cette solution ne me paraît pas vraiment satisfaisante.
Merci d'avance de votre réponse.

#4 Re : Général » Résultat d'une fonction » 08/12/2014 17:00:08

Merci beaucoup pour votre réponse.


Ce n'est pas juste une optimisation: dans la question initiale, la manière donc la fonction est combinée avec la requête pour calculer un aggrégat est réellement absurde en logique SQL.

C'est bien mon problème: je ne suis pas familier de "la logique "SQL"!


tout peut être aggrégé en une seule requête comme proposé plus haut, le SUM(CASE...) donnant bien le résultat attendu.

Pas tout à fait cependant: la solution passant par une fonction permet de n'afficher aucun résultat lorsque l'un des éléments de la somme est absent, ce qui n'est pas le cas avec sum(case...), qui renvoie systématiquement un résultat, que tous les termes de la somme soient présents ou non.
J'avais au départ choisi de passer par une fonction car ce que j'ai décrit plus haut ne représente qu'une étape intermédiaire: mon but est de créer une requête qui, à l'horodate h, renvoie la somme suivante:
               la durée t1 à l'horodate h
            + la durée t2 à l'horodate h+t1
            + la durée t3 à l'horodate h+t1+t2
            etc.
Je ne vois pas bien comment écrire cette itération sans passer par une fonction comme celle-ci, qui a priori fait bien le boulot :

CREATE OR REPLACE FUNCTION "ma_fonction2"(timestamp without time zone)
  RETURNS smallint AS
$BODY$
	DECLARE RESULTAT numeric;
		t1 numeric;
		t2 numeric;
		t3 numeric;
		t4 numeric;
		t5 numeric;
BEGIN
SELECT INTO t1 duree FROM ma_table_donnees WHERE champ = 'x1' AND horodate = $1;		
SELECT INTO t2 duree FROM ma_table_donnees WHERE champ = 'x2' AND horodate = $1 + (round (0.46*t1/60)) * interval '1 minute';
SELECT INTO t3 duree FROM ma_table_donnees WHERE champ = 'x3' AND horodate = $1 + (round ((0.46*t1 + t2)/60)) * interval '1 minute';
SELECT INTO t4 duree FROM ma_table_donnees WHERE champ = 'x4' AND horodate = $1 + (round ((0.46*t1 + t2 + t3)/60)) * interval '1 minute';
SELECT INTO t5 duree FROM ma_table_donnees WHERE champ = 'x5' AND horodate = $1 + (round ((0.46*t1 + t2 + t3 + t4)/60)) * interval '1 minute';
RESULTAT = t1*0.46+t2+t3+t4+t5*1.19;
RETURN round(RESULTAT);
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION "ma_fonction2"(timestamp without time zone)
  OWNER TO postgres;

Cette fonction vous paraît-elle également absurde? Comment aurais-je dû procéder?

#5 Re : Général » Résultat d'une fonction » 05/12/2014 14:39:12

A priori en modifiant ma requête d'insertion comme ceci:

INSERT INTO ma_table_resultat
        SELECT DISTINCT(horodate), ma_fonction(horodate) FROM ma_table_donnees;

ça fonctionne. Ce n'est pas très élégant ni optimal à ce qu'il me semble, mais cela permet d'éluder le problème. Qu'en pensez-vous?

#6 Re : Général » Résultat d'une fonction » 05/12/2014 13:34:37

Merci pour ces réponses.

L'objectif poursuivi semble être une aggrégation sur l'horodate, l'aggrégat étant le résultat de la fonction montrée.

Une agrégation de plusieurs valeurs à la même horodate oui.

Dans ce cas, ça ne peut pas marcher tel que montré, d'abord parce qu'une fonction aggrégat nécessite un CREATE AGGREGATE et un codage spécifique, ensuite parce que la requête doit avoir un GROUP BY.

Le problème est que je n'ai pas besoin de TOUTES les données de la même horodate. Sinon effectivement il aurait été simple de faire SELECT sum(...) FROM TABLE GROUP BY horodate.

dverite a écrit :

Ce qu'il faut comprendre c'est que quand on fait "select fonction(x) from table" et que la table contient 20 lignes, on obtient 20 résultats. Peu importe que la fonction elle-même aille chercher d'autres lignes dans la même table et fasse des additions.

Je ne suis pas sûr de bien comprendre. Ma table de données doit faire 1000 à 2000 lignes, la fonction devrait donc retourner 1000 lignes par horodate et pas 20 non?

dverite a écrit :

Le résultat voulu et qui est conforme à la logique SQL se rapproche peut-être de ça (ne nécessite pas fonction plpgsql):

select 
 horodate,
 sum(
   case when champ=x1 then t1*0.46
            when champ=x2 then t2
           ... etc...
            else 0 end
    )
 GROUP BY horodate;

Est-ce que cette formulation "case when ... then" renvoie bien la valeur t1 qui correspond à la ligne pour laquelle champ = x1? Ce n'a pas l'air évident.

Ce qui resterait assez bizarre c'est ce que représentent ces x1, x2,... On s'attendrait à des constantes litérales (nom du champ dans une table Entité-valeur) alors que syntaxiquement ici c'est un nom de colonne.

x1, etc sont bien des valeurs de la colonne "champ"(character varying).

#7 Re : Général » Résultat d'une fonction » 05/12/2014 12:41:39

Un exemple complet? De quels autres renseignements auriez-vous besoin?

#8 Général » Résultat d'une fonction » 05/12/2014 12:12:55

XPBT
Réponses : 8

Bonjour,
voici mon problème du jour:
j'ai une table ma_table_donnees avec trois colonnes champ (character varying), horodate(timestamp without time zone) et duree(numeric), avec une clé primaire (champ, horodate)). J'ai besoin de faire une somme de ces durees pour certains champs, à toutes les horodates. Je souhaite injecter cette somme dans une autre table ma_table_resultat, qui contient deux colonnes horodate et resultat(smallint).
J'ai donc créé une fonction:

CREATE OR REPLACE FUNCTION "ma_fonction"(timestamp without time zone)
  RETURNS smallint AS
$BODY$
    DECLARE RESULTAT numeric;
        t1 numeric;
        t2 numeric;
        t3 numeric;
        t4 numeric;
        t5 numeric;
BEGIN
SELECT INTO t1 duree FROM ma_table_donnees WHERE champ = x1 AND horodate = $1;       
SELECT INTO t2 duree FROM ma_table_donnees WHERE champ = x2 AND horodate = $1;
SELECT INTO t3 duree FROM ma_table_donnees WHERE champ = x3 AND horodate = $1;
SELECT INTO t4 duree FROM ma_table_donnees WHERE champ = x4 AND horodate = $1;
SELECT INTO t5 duree FROM ma_table_donnees WHERE champ = x5 AND horodate = $1;
RESULTAT = t1*0.46+t2+t3+t4+t5*1.19;
RETURN round(RESULTAT);
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION "ma_fonction"(timestamp without time zone)
  OWNER TO postgres;

Ensuite j'exécute la commande:

INSERT INTO ma_table_resultat
        SELECT horodate, ma_fonction(horodate) FROM ma_table_donnees;

Ça fonctionne, j'obtiens bien le résultat attendu pour chaque horodate. Le problème est que j'obtiens ce résultat en une vingtaine d'exemplaires (ma_table_resultat contient une vingtaine de lignes avec un résultat identique pour chaque horodate). Évidemment ce n'est pas le but, j'aimerais bien avoir une seule ligne et un seul résultat par horodate.
Je ne connais pas assez bien le fonctionnement de Postgre et du langage SQL pour comprendre ce qui se passe lors de l'exécution de cette fonction et qui conduit à dupliquer les résultats. Quelqu'un pourrait-il éclairer ma lanterne?
Merci d'avance.

#9 Re : Général » COPY / pb de chemin » 04/12/2014 17:16:58

Effectivement \copy me crée bien un fichier en local. Par contre, lorsque je veux réimporter ce fichier dans une table en local (même structure que la table distante d'origine) avec "COPY FROM", un message d'erreur me dit que certains champs ne sont pas renseignés. Bizarre non?

Tout dépend de votre application cliente. C'est en effet ce que fait psql, quand on utilise le \copy. Quant aux autres applications, faut voir...

J'utilise pgAdmin. Si je fais "COPY TO STDOUT" puis "COPY FROM STDIN" n'est-ce pas sensé marcher?

Merci beaucoup pour votre aide.

#10 Re : Général » COPY / pb de chemin » 04/12/2014 15:34:22

Et si je fais COPY TO STDOUT ça n'est pas sensé copier les données vers mon application cliente?

#11 Re : Général » COPY / pb de chemin » 04/12/2014 15:23:31

C'est bien ce que je pensais. Pouvez-vous préciser comment utiliser cette "métacommande"?
Merci beaucoup.

#12 Général » COPY / pb de chemin » 04/12/2014 14:46:36

XPBT
Réponses : 6

Bonjour,
encore une question débutant:
je me sers de la fonction COPY avec l'instruction suivante : COPY (SELECT x FROM y) TO 'C:\tmp\transfert_data'  (DELIMITER ',');
Ça marche très bien lorsque je me connecte à une base en local; par contre, ça ne marche plus du tout lorsque je me connecte à une base distante, avec le message d'erreur "un chemin relatif n'est pas autorisé à utiliser l'instruction copy".  Dois-je écrire différemment le chemin de mon fichier?
Ou alors est-ce à dire que COPY ne permet pas de copier les données d'une base distante en local ? Comment puis-je m'y prendre dans ce cas pour récupérer les données d'une table d'une base distante et les réinjecter dans une table d'une base en local?
Merci d'avance pour vos réponses!

#14 Général » Conversion de type » 01/12/2014 16:27:54

XPBT
Réponses : 2

Bonjour,
je débute avec PostgreSQL, à tel point que même la documentation officielle m'embrouille parfois plus qu'elle ne m'aide!
Voici mon problème: j'ai une table avec une colonne "date et heure" (timestamp without time zone) et une colonne "temps" (integer), dont les valeurs représentent des durées en secondes. Je souhaiterais additionner les deux, en d'autres termes incrémenter le champ "date et heure" avec la valeur de la colonne "temps" correspondante. Mais je n'arrive pas à faire la conversion de type proprement entre timestamp et integer (sachant que je voudrais obtenir une valeur de type timestamp en sortie).
C'est certainement un problème simplissime pour la plupart d'entre vous, alors merci d'avance si vous pouvez m'aider.
Bonne journée!

Pied de page des forums

Propulsé par FluxBB