#1 Mon 24 October 2011 17:12
- mcdelay
- Participant occasionnel
- Lieu: Lille
- Date d'inscription: 19 Sep 2005
- Messages: 25
Requete spatiale postGIS
Bonjour,
Je démarre juste avec les requêtes spatiales sous postGIS et je cherche à faire une requête spatiale entre 3 couches mais je m'emmêle les pinceaux.
J'ai 3 tables une couche de point (point de collecte), et 2 couches de polygone (zone et batiment). Je cherche a savoir pour un point de collecte, le nombre de bâtiment se trouvant dans la zone la plus proche d'un point de collecte. En gros j'ai 2 requêtes et il faudrait que je les imbrique !
1er : pour connaître le nombre de bâtiment dans une zone
Code:
SELECT COUNT(DISTINCT(bati.ogc_fid)) AS nbreLogement FROM zone LEFT JOIN bati Intersects(bati.the_geom , zone.the_geom)
2ième: pour connaître et sélectionner la zone la plus proche d'un point de collecte
Code:
SELECT zone.ogc_fid, Distance(zone.the_geom ,Pointcollecte.the_geom) FROM zone, Pointcollecte ORDER BY Distance ASC LIMIT 1
(Peut être faut-il écrire cette dernière autrement ...)
Petite question, quelle est la différence entre utiliser le préfixe ST par exemple ST_Intersect et Intersect ? D'après ce que je comprends, c'est un histoire d'indexation sur le champ the_geom, qu'est ce que cela implique concrêtement ?
Merci !
Hors ligne
#2 Mon 24 October 2011 18:02
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: Requete spatiale postGIS
Bonjour,
Je démarre juste avec les requêtes spatiales sous postGIS et je cherche à faire une requête spatiale entre 3 couches mais je m'emmêle les pinceaux.
J'ai 3 tables une couche de point (point de collecte), et 2 couches de polygone (zone et batiment). Je cherche a savoir pour un point de collecte, le nombre de bâtiment se trouvant dans la zone la plus proche d'un point de collecte. En gros j'ai 2 requêtes et il faudrait que je les imbrique !
1er : pour connaître le nombre de bâtiment dans une zoneCode:
SELECT COUNT(DISTINCT(bati.ogc_fid)) AS nbreLogement FROM zone LEFT JOIN bati Intersects(bati.the_geom , zone.the_geom)2ième: pour connaître et sélectionner la zone la plus proche d'un point de collecte
Code:
SELECT zone.ogc_fid, Distance(zone.the_geom ,Pointcollecte.the_geom) FROM zone, Pointcollecte ORDER BY Distance ASC LIMIT 1(Peut être faut-il écrire cette dernière autrement ...)
Petite question, quelle est la différence entre utiliser le préfixe ST par exemple ST_Intersect et Intersect ? D'après ce que je comprends, c'est un histoire d'indexation sur le champ the_geom, qu'est ce que cela implique concrêtement ?
Merci !
Bonsoir,
Pour faire ceci en une seule requete, il faut utiliser quelques "tricks" de postgresql, PostGIS < 2.0 ne possedant pas encore d'operateur Nearest Neighbors:
Le principe est de choisir en premier les zones les plus proches des points de collecte, puis de regarder les batiments inclus (ou intersectant, suivant votre cas) dans les zones (non testé dans votre cas):
Code:
with plus_proche as ( select distinct on(z.ogc_fid) ogc_fid, distance(z.the_geom ,pt.the_geom) as d, z.geom as zone_geom from zone z, Pointcollecte pt where st_dwithin(z.geom, pt.geom, 500) order by d ) select pt_ogc_fid, count(b.ogc_fid) as nbrelogement from bati b where st_within(b.geom, zone_geom) group by pt_ogc_fid;
La premiere requete, obtenue avec la clause WITH, tente de lister les zones les plus proches de chaque point et ne garde que le premier candidat => le plus proche.
Pour cela, l'operateur st_dwithin est utilisé avec une distance fixée en dur, c'est la que le bât blesse: il faut connaitre ou estimer la distance max au dela de laquelle aucun point n'est dans une zone.
Ensuite, la deuxieme requete utilise la premiere pour compter le nombre de batiments dans chaque zone la plus proche du point de collecte.
Concernant la difference entre st_ et pas st_, deux choses:
• L'adoption par Postgis de la norme SQL MM impose de nommer les fonctions st_, pour plus de clarté et les séparer des autres fonctions de la base.
• Historiquement, dans postgis, l'utilisation des index spatiaux n'etait pas automatique lors de clauses where, mais necessitait d'utiliser l'operateur &&. Lors de la mise en conformité des noms de fonctions, il a ete décidé d'ajouter en plus, dans les fonctions st_*, un appel automatique a l'index, histoire de rendre nos vie plus faciles ( )
Concretement, si vous faites des selects sans preciser de clause where ou de jointure spatiale, aucune différence entre les deux notations.
Dans l'autre cas: jointures spatiales, alors ne pas utiliser les index, c'est prendre le risque de requetes prenant beaucoup de temps (qd je dis beaucoup, un index spatial peut faire tomber le temps de requete de plusieurs heures a 1s).
Dans votre cas, la creation d'index spatiaux sur chaque colonne geo de vos tables est indispensable.
Nicolas
Dernière modification par Nicolas Ribot (Mon 24 October 2011 21:34)
Hors ligne
#3 Mon 24 October 2011 21:38
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: Requete spatiale postGIS
Dans une version un peu plus propre:
with plus_proche as (
select distinct on(pt.ogc_fid) pt.ogc_fid as pt_id,
z.ogc_fid as zone_id,
z.the_geom as zone_geom
from zone z, Pointcollecte pt
where st_dwithin(z.the_geom, pt.the_geom, 500)
order by pt.ogc_fid, distance(z.the_geom, pt.the_geom)
) select p.pt_id, p.zone_id, count(b.ogc_fid) as nbrelogement
from bati b, plus_proche p
where st_within(b.the_geom, p.zone_geom)
group by p.pt_id, p.zone_id;
Cela liste, pour chaque point de collecte, la zone la plus proche et le nombre de bâtiments qui s'y trouvent.
La distance arbitraire de 500m doit être ajustée en fonction des données: c'est la distance maximale entre les points de collecte et les zones.
S'il y a beaucoup de points de collecte par rapport au nombre de zones, ça peut être intéressant de calculer dans un premier temps le nombre de bâtiments par zone.
Nicolas
Hors ligne
#4 Wed 26 October 2011 15:27
- mcdelay
- Participant occasionnel
- Lieu: Lille
- Date d'inscription: 19 Sep 2005
- Messages: 25
Re: Requete spatiale postGIS
Nicolas,
Merci beaucoup pour ta réponse ! Ca fonctionne très bien et ça m'a permis de faire ma première requête spatiale complexe ;-)
J'ai utilisé la requête de ton deuxième message et je l'ai réadaptée à mes besoins. Petite question pour que je comprenne bien, le order de la première requête permet de classer les zones par distance et quel est l'élément permettant de ne prendre que la zone la plus proche ppur un point de collecte ?
Merci
Hors ligne
#5 Wed 26 October 2011 16:44
- Nicolas Ribot
- Membre
- Lieu: Toulouse
- Date d'inscription: 9 Sep 2005
- Messages: 1554
Re: Requete spatiale postGIS
Nicolas,
Merci beaucoup pour ta réponse ! Ca fonctionne très bien et ça m'a permis de faire ma première requête spatiale complexe ;-)
Ah cool.
J'ai utilisé la requête de ton deuxième message et je l'ai réadaptée à mes besoins. Petite question pour que je comprenne bien, le order de la première requête permet de classer les zones par distance et quel est l'élément permettant de ne prendre que la zone la plus proche ppur un point de collecte ?
Merci
oui, le premier ordre by permet de classer par distance croissante. Puis le distinct on de la partie select ne garde que le premier record parmi ceux qui partagent le meme pt_ogc_fid.
Ce n'est pas SQL 92, mais c'est une fonction de Postgresql bien pratique. Ca permet d'eliminer des lignes qui partagent un ou plusieurs attributs communs (mais pas tous: ici la distance change a chaque record. Un DISTINCT traditionnel aurait gardé toutes les zones pour chaque point de collecte).
Nico
Dernière modification par Nicolas Ribot (Wed 26 October 2011 16:46)
Hors ligne