Vous n'êtes pas identifié(e).
Pages : 1
Bonjour,
J'ai un souci avec une requête où le LEFT JOIN ne renvoie pas toutes les lignes de la table de gauche, mais ignore les lignes renvoyant une valeur nulle. La requête utilisée utilise une fonction PostGIS sur une colonne stockant de la géométrie mais ce n'est pas bloquant pour la compréhension, le problème étant du SQL pur à mon sens. Deux tables sont appelées :
- geo : gid, insee, date, the_geom
- periode :
gid | libelle | debut | fin
-------+----------------+---------+----------
1 | 2005 - 2014 | 2005 | 2014
1 | 1995 - 2004 | 1995 | 2004
1 | 1985 - 1994 | 1985 | 1994
1 | 1975 - 1984 | 1975 | 1984
1 | 1965 - 1974 | 1965 | 1974
1 | 1945 - 1964 | 1945 | 1964
1 | avant 1945 | 0 | 1944
SELECT
periode.libelle AS periode,
coalesce(sum(st_length(geo.the_geom)), 0) AS length
FROM periode
LEFT JOIN geo ON geo.date BETWEEN periode.debut AND periode.fin
WHERE geo.insee = '086009'
GROUP BY periode.libelle, periode.gid
ORDER BY periode.gid DESC ;
Résultat de la requête : il manque la ligne « avant 1945 » car aucune date ne correspond à cette tranche dans ma table geo.
periode | length
----------------+-----------
2005 - 2014 | 103
2005 - 2014 | 56
1985 - 1994 | 18
1975 - 1984 | 5.7
1965 - 1974 | 5.3
1945 - 1964 | 0.2
Si je supprime la clause WHERE, le problème n'existe plus puisque j'ai des dates renseignées pour chaque période (je récupère bien mes 7 lignes).
Problème SQL classique je pense, mais je ne vois pas pourquoi le LEFT JOIN ne retourne pas l'ensemble des lignes...
Merci pour votre aide !
Thomas
Dernière modification par Thomas Williamson (04/06/2014 16:00:59)
Hors ligne
Bonjour,
J'ai lu en diagonale, mais.. à tout hasard, avez-vous essayé :
* de remplacer LEFT par RIGHT?
* de changer le where en : WHERE (geo.insee = '086009' or geo.insee is null)
(pas trop le temps de vous répondre plus là :-(... plus tard peut-être)
Bien à vous,
Jean-Paul Argudo
https://www.postgresql.fr
https://www.crunchydata.com
Hors ligne
Oui bien sûr, ça donne ça (logique : la ligne vide correspond aux dates non reseignées) :
periode | length
----------------+-----------
| 87
2005 - 2014 | 103
2005 - 2014 | 56
1985 - 1994 | 18
1975 - 1984 | 5.7
1965 - 1974 | 5.3
1945 - 1964 | 0.2
Hors ligne
Re, voir le commentaire modifié entre temps plus haut:
* de changer le where en : WHERE (geo.insee = '086009' or geo.insee is null)
Jean-Paul Argudo
https://www.postgresql.fr
https://www.crunchydata.com
Hors ligne
Je viens de tester, ça ne change rien... Je n'ai aucune ligne pour lesquelles le code insee n'est pas renseigné.
Hors ligne
SELECT
periode.libelle AS periode,
coalesce(sum(st_length(geo.the_geom)), 0) AS length
FROM periode
LEFT JOIN geo ON geo.date
WHERE geo.insee = '086009'
and ((geo.date BETWEEN periode.debut AND periode.fin) or (geo.date is null))
GROUP BY periode.libelle, periode.gid
ORDER BY periode.gid DESC ;
... donne quoi?
Jean-Paul Argudo
https://www.postgresql.fr
https://www.crunchydata.com
Hors ligne
RE,
D'ailleurs je me dis que cette jointure est bien curieuse, ... et que faire un coalesce après un sum aussi
Voici donc ce que je vous propose:
SELECT
periode.libelle AS periode,
sum(coalesce(st_length(geo.the_geom),0)) AS length
FROM periode
LEFT JOIN geo ON geo.date = periode.date
WHERE geo.insee = '086009'
and ((geo.date BETWEEN periode.debut AND periode.fin) or (geo.date is null))
GROUP BY periode.libelle, periode.gid
ORDER BY periode.gid DESC ;
... en supposant que vos dates sont des entiers pleins genre 2014 d'un côté et 2014 de l'autre...
... si ça n'était pas le cas:
LEFT JOIN geo ON extract(year from geo.date) = periode.date
... voilà
Jean-Paul Argudo
https://www.postgresql.fr
https://www.crunchydata.com
Hors ligne
Heu... ça marche oui et non : la ligne « avant 1945 » est bien renvoyée mais les chiffres sortis sont aberrants... Je ne dois pas mélanger les dates non renseignées puisque je travaille justement sur les dates renseignées.
Dernière modification par Thomas Williamson (04/06/2014 11:26:24)
Hors ligne
Les dates sont des entiers pleins, mais... je n'ai pas de colonne date dans ma table periode (cf. mon premier mail). Je ne comprends pas votre réponse de 10:14.
Hors ligne
Re,
Pouvez vous poster un exemple de données/structure de la table géo?
Sans cela j'aurai du mal à reproduire de mon côté;
Bien à vous,
Jean-Paul Argudo
https://www.postgresql.fr
https://www.crunchydata.com
Hors ligne
Pouvez vous poster un exemple de données/structure de la table géo?
oui ca serait plus facile!
Avez vous essayé déjà un simple select sans regroupement pour voir ce que ca renvoie?
Hors ligne
Solution trouvée en supprimant la clause WHERE et en passant le filtre sur le code insee dans la jointure gauche directement :
SELECT
periode.libelle AS periode,
coalesce(sum(st_length(geo.the_geom)), 0) AS length
FROM periode
LEFT JOIN geo ON geo.date BETWEEN periode.debut AND periode.fin AND geo.insee = '086009'
GROUP BY periode.libelle, periode.gid
ORDER BY periode.gid DESC ;
Thomas
Hors ligne
Pages : 1