Chapitre 4. Utiliser PostGIS
4.1. Objets SIG
Les objets SIG supportés par PostGIS sont un sur-ensemble des "Fonctionnalités Simples" définies par l'OpenGIS Consortium (OGC). Depuis la version 0.9, PostGIS gère tous les objets et fonctions définis dans les spécifications "Simple Features Specifications for SQL" de l'OGC.
PostGIS étend les standards en ajoutant le support pour les coordonnées 3DZ, 3DM et 4D.
haut de la page | table des matières 4.1.1. Les formats WKB et WKT de l'OpenGIS
Les spécifications de l'OpenGIS définissent deux méthodes standards pour décrire les objets spatiaux : la forme "textuelle bien connue" et la forme "binaire bien connue". Les deux formats contiennent des informations sur le type de l'objet ainsi que sur ses coordonnées.
Exemples de représentation en WKT d'objets spatiaux dont voici la description :
- POINT(0 0)
- LINESTRING(0 0,1 1,1 2)
- POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))
- MULTIPOINT(0 0,1 2)
- MULTILINESTRING((0 0,1 1,1 2),(2 3,3 2,5 4))
- MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))
- GEOMETRYCOLLECTION(POINT(2 3),LINESTRING((2 3,3 4)))
Les spécifications de l'OpenGIS imposent également que le format de stockage interne des objets géographiques inclue un identifiant du système de références spatiales ("spatial referencing system identifier", SRID). Le SRID est obligatoire lors de la création d'objets géographiques dans la base de données.
La gestion des entrées/sorties dans ces formats est rendue possible grâce aux fonctions suivantes :
bytea WKB = ST_asBinary(geometry);
text WKT = ST_asText(geometry);
geometry = ST_GeomFromWKB(bytea WKB, SRID);
geometry = ST_GeometryFromText(text WKT, SRID);
Par exemple, voici des commandes valides pour créer et insérer des objets géographiques OGC :
INSERT INTO SPATIALTABLE (
THE_GEOM,
THE_NAME
)
VALUES (
ST_GeomFromText('POINT(-126.4 45.32)', 312),
'A Place'
)
haut de la page | table des matières 4.1.2. PostGIS EWKB, EWKT et formes canoniques
Les formats proposés par l'OGC gèrent seulement la 2D et le SRID associé n'est jamais embarqué dans la représentation en entrée/sortie.
Les formats étendus de PostGIS sont actuellement un sur-ensemble de ceux de l'OGC (chaque WKB/WKT valide est un EWKB/EWKT valide) mais cela pourrait changer à l'avenir, particulièrement si l'OGC venait à sortir un nouveau format qui serait en conflit avec nos extensions. Donc vous NE DEVRIEZ PAS compter sur cette propriété.
Les format EWKB/EWKT de PostGIS ajoute les gestions de système de coordonnées 3dm, 3dz et 4d et contiennent l'information relative au SRID.
Des exemples de la représentation textuelle (EWKT) d'objets spatiaux étendus des propriétés sont les suivantes :
- POINT(0 0 0) -- XYZ
- SRID=32632;POINT(0 0) -- XY avec un SRID
- POINTM(0 0 0) -- XYM
- POINT(0 0 0 0) -- XYZM
- SRID=4326;MULTIPOINTM(0 0 0,1 2 1) -- XYM avec un SRID
- MULTILINESTRING((0 0 0,1 1 0,1 2 1),(2 3 1,3 2 1,5 4 1))
- POLYGON((0 0 0,4 0 0,4 4 0,0 4 0,0 0 0),(1 1 0,2 1 0,2 2 0,1 2 0,1 1 0))
- MULTIPOLYGON(((0 0 0,4 0 0,4 4 0,0 4 0,0 0 0),(1 1 0,2 1 0,2 2 0,1 2 0,1 1 0)),((-1 -1 0,-1 -2 0,-2 -2 0,-2 -1 0,-1 -1 0)))
- GEOMETRYCOLLECTIONM(POINTM(2 3 9),LINESTRINGM((2 3 4,3 4 5)))
Les entrées/sorties dans ces formats sont disponibles via les interfaces suivantes :
- bytea EWKB = ST_asEWKB(geometry);
- text EWKT = ST_asEWKT(geometry);
- geometry = ST_GeomFromEWKB(bytea EWKB);
- geometry = ST_GeomFromEWKT(text EWKT);
Par exemple, une requête d'insertion valide pour créer et insérer un objet spatial PostGIS pourrait être :
INSERT INTO SPATIALTABLE (
THE_GEOM,
THE_NAME
)
VALUES (
ST_GeomFromEWKT('SRID=312;POINTM(-126.4 45.32 15)'),
'A Place'
)
Les "formes canoniques" d'un type PostgreSQL sont les représentations que vous obtenez avec de simples requêtes (sans appel de fonctions) et celle qui est sûr d'être accepté avec un simple insert, update ou copy. Pour le type geometry
de PostGIS se sont les suivantes :
- Sortie -
binaire : EWKB
ascii : HEXEWKB (EWKB sous la forme hexadécimale)
- Entrée -
binaire : EWKB
ascii : HEXEWKB|EWKT
Par exemple cette requêtes lit du EWKT
et renvoie du HEXEWKB
dans le processus d'entrée/sortie canonique ascii
:
=# SELECT 'SRID=4;POINT(0 0)'::geometry;
geometry
----------------------------------------------------
01010000200400000000000000000000000000000000000000
(1 row)
haut de la page | table des matières 4.1.3. SQL-MM Partie 3
Les spécifications des applications multimédia spatiales SQL étendent les propriétés simples des spécifications SQL en définissant un nombre de "courbes circulairement interpolées"
(original : "a number of circularly interpolated curves").
Les définitions de SQL-MM incluent les coordonées 3dm, 3dz et 4d, mais ne permettent pas d'embarquer l'information pour le SRID
.
Les extensions "texte bien-connu" ne sont pas totalement supportées. Des exemples de quelque géométries courbées sont disponibles ci-dessous :
- CIRCULARSTRING(0 0, 1 1, 1 0)
CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0)
Le type CIRCULARSTRING
est le type de base des courbes, semblable à un élément de type LINESTRING
dans le monde linéaire. Un ségment seul nécessite 3 points, les points de départ et d'arrivé (le premier et le troisième) et un autre point sur l'arc. À l'exception des cercles fermés, pour lesquels le poinr de départ et d'arrivé sont les mêmes.Dans ce cas, le deuxième point DOIT être le centre du cercle. Pour assembler les arcs ensemble, le dernier point du l'arc précédent devient le premier du suivant, exactement comme pour les géométries de type LINESTRING
. Cela signifie qu'une chaîne circulaire valide doit avoir un nombre impair de points supérieur à 1.
- COMPOUNDCURVE(CIRCULARSTRING(0 0, 1 1, 1 0),(1 0, 0 1))
Une courbe composée est une courbe simple et continue qui a à la fois des segments courbes (circulaires) et des segments linéaires. Cela signifie que en plus d'avoir des composants bien formés, le point final de chaque composant (à l'exception du dernier) doit coincider avec le point de départ de l'élément suivant.
- CURVEPOLYGON(CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0),(1 1, 3 3, 3 1, 1 1))
Exemple de courbes composée dans un polygone courbe : CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,2 0, 2 1, 2 3, 4 3),(4 3, 4 5, 1 4, 0 0)), CIRCULARSTRING(1.7 1, 1.4 0.4, 1.6 0.4, 1.6 0.5, 1.7 1) )
Un objet de type CURVEPOLYGON
est simplement un polygone, avec une partie extérieure et aucune ou plusieurs parties intérieures. La différence réside dans le fait que les différentes parties qui composent le polygone sont des courbes, des lignes ou des courbes composées.
Depuis sa version 1.4 PostGIS supporte les coubres composées dans un polygon courbe.
- MULTICURVE((0 0, 5 5),CIRCULARSTRING(4 0, 4 4, 8 4))
Un objet de type MULTICURVE
est une collection de courbes, qui peut contenir des lignes, des courbes et des courbes composées.
- MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0),(1 1, 3 3, 3 1, 1 1)),((10 10, 14 12, 11 10, 10 10),(11 11, 11.5 11, 11 11.5, 11 11)))
C'est une collection de surfaces qui peut contenir des polygones linéaires ou courbes.
Les versions précédentes de la version 1.4 de PostGIS ne supportent pas les courbes composées dans les polygones courbes, mais les versions supérieures ou égales à la version 1.4 supporte l'utilisation de courbes composées dans les polygones courbes.
Note : tout les comparaisons à virgule flottante dans l'implémentation de SQL-MM
sont effectuées avec une tolérance spécifiée, actuellement fixée à 1e-8
.
haut de la page | table des matières 4.2. Utilisation des standards de l'OpenGIS
La spécification "Simple Features for SQL" de l'OpenGIS definie les types d'objets géographiques standards, les fonctions necessaires pour les manipuler et un ensemble de tables de méta-données. Pour s'assurer que les méta-données seront toujours complètes, les opérations telles que créer ou supprimer une colonne géométrique sont effectuées selon certaines procédures définies par l'OpenGIS.
Il y a deux tables de méta-données OpenGIS : SPATIAL_REF_SYS et GEOMETRY_COLUMNS. La table SPATIAL_REF_SYS contient les identifiants numériques et la description textuelle des systèmes de coordonnées utilisés dans la base de données.
haut de la page | table des matières 4.2.1. La table SPATIAL_REF_SYS
La table spatial_ref_sys
est inclue dans PostGIS et est conforme aux spécifications de l'OGC, elle contient environ 3000 systèmes de références spatiales et les détails nécessaires à la transformation/reprojection entre eux.
Bien que la table spatial_ref_sys
contienne environ 3000 des systèmes de références spatiales les plus communément utilisés qui sont gérés par la librairie Proj4, elle ne contient pas tout les systèmes de références spatiales connue et vous pouvez même définir vos propres systèmes si vous êtes familiers avec la syntaxe de Proj4. Gardez à l'esprit que la plupart des systèmes de références spatiales sont régionaux et n'ont pas de signification hors de leurs limites respectives.
Une ressource essentiel pour la recherche de systèmes de références spatiales qui ne seraient pas présent dans la table spatial_ref_sys est le site web http://spatialreference.org/.
Les systèmes de références spatiales les plus couramment utilisés sont : 4326 - WGS 84 Long Lat, 4269 - NAD 83 Long Lat, 3395 - WGS 84 World Mercator, 2163 - US National Atlas Equal Area, les systèmes de références spatiales pour les zones NAD 83, WGS 84 UTM zone - UTM sont idéaux pour mesurer, mais couvrent uniquement des régions de 6 degrés.
Pour des détails sur la détermination de la zone UTM à utiliser pour votre espace d'intérêts, utilisez la fonction plpgsql de PostGIS : utmzone
.
Voici la définition de la table SPATIAL_REF_SYS :
CREATE TABLE SPATIAL_REF_SYS (
SRID INTEGER NOT NULL PRIMARY KEY,
AUTH_NAME VARCHAR(256),
AUTH_SRID INTEGER,
SRTEXT VARCHAR(2048),
PROJ4TEXT VARCHAR(2048)
)
Et voici les colonnes de SPATIAL_REF_SYS :
- SRID : Un entier qui identifie de façon unique le système de références spatiales (SRS) de la base.
- AUTH_NAME : Le nom du système de référence. Par exemple, "EPSG"
- AUTH_SRID : L'identifiant du SRS définie par l'autorité cité dans le AUTH_NAME. Dans le cas "EPSG", c'est celui pour lequel on utilise EPSG.
- SRTEXT : La représentation Well-Known Text (WKT) du SRS. Exemple:
PROJCS["NAD83 / UTM Zone 10N",
GEOGCS["NAD83",
DATUM["North_American_Datum_1983",
SPHEROID["GRS 1980",6378137,298.257222101]
],
PRIMEM["Greenwich",0],
UNIT["degree",0.0174532925199433]
],
PROJECTION["Transverse_Mercator"],
PARAMETER["latitude_of_origin",0],
PARAMETER["central_meridian",-123],
PARAMETER["scale_factor",0.9996],
PARAMETER["false_easting",500000],
PARAMETER["false_northing",0],
UNIT["metre",1]
]
Pour une liste des codes de projection EPSG et leur correspondance en WKT, suivez ce lien. Pour des explications sur le WKT, voir OpenGIS "Coordinate Transformation Services Implementation Specification".
Pour des informations sur "the European Petroleum Survey Group" (EPSG) et leur base de SRS voir ceci.
- PROJ4TEXT : PostGIS utilise la librairie Proj4 pour offrir les possibilités de transformations de coordonnées. La colonne PROJ4TEXT contient les définitions de coordonnées Proj4 pour un SRID particulier. Exemple:
+proj=utm +zone=10 +ellps=clrk66 +datum=NAD27 +units=m
Pour plus d'information, voir Le site web Proj4.
Le fichier spatial_ref_sys.sql contient les définitions de SRTEXT et de PROJ4TEXT pour toutes les projections EPSG.
haut de la page | table des matières 4.2.2. La table GEOMETRY_COLUMNS
La définition de la table GEOMETRY_COLUMNS est la suivante :
CREATE TABLE GEOMETRY_COLUMNS (
F_TABLE_CATALOG VARCHAR(256) NOT NULL,
F_TABLE_SCHEMA VARCHAR(256) NOT NULL,
F_TABLE_NAME VARCHAR(256) NOT NULL,
F_GEOMETRY_COLUMN VARCHAR(256) NOT NULL,
COORD_DIMENSION INTEGER NOT NULL,
SRID INTEGER NOT NULL,
TYPE VARCHAR(30) NOT NULL
)
Les colonnes sont les suivantes :
- F_TABLE_CATALOG, F_TABLE_SCHEMA, F_TABLE_NAME : le nom totalement qualifié de la table de propriétés contenant la colonne géométrique. Notez que le terme de "catalog" et "schema" sont propre à Oracle. Il n'y a pas d'équivalent à "catalog" dans PostgreSQL, cette colonne reste donc vide -- en ce qui concerne "schema", le nom du schema PostgreSQL est utilisé (la valeur par défaut est public).
- F_GEOMETRY_COLUMN : le nom de la colonne géométrique dans la table propriété.
- COORD_DIMENSION : la dimention spatiale (2,3 ou 4) de la colonne.
- SRID : l'identifiant du système de référence spatiale utilisée pour les coordonnées géométiques dans cette table. C'est une clef étrangère faisant référence à la table SPATIAL_REF_SYS.
- TYPE : le type d'objet géographique. Pour réstreindre la colonne spatiale à un type unique, utilisez l'un des types : POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION ou les versions correspondante XYM : POINTM, LINESTRINGM, POLYGONM, MULTIPOINTM, MULTILINESTRINGM, MULTIPOLYGONM, GEOMETRYCOLLECTIONM. Pour des types de collections hétérogènes (contenant plusieurs types), vous pouvez utiliser "GEOMETRY" comme type.
NOTE :
Cet attribut ne fait (probablement) pas partie des spécifications de l'OpenGIS, mais est requit pour assurer l'homégénéïté des types.
haut de la page | table des matières 4.2.3. Créer une table spatiale
Créer une table avec des données géographiques se déroule en deux étapes :
- Créer une table (non-spatialisée) normale. Par exemple :
CREATE TABLE ROADS_GEOM ( ID int4, NAME varchar(25) )
- Ajouter à la table la colonne spatiale en utilisant la fonction "AddGeometryColumn" de l'OpenGIS.
La syntaxe est la suivante :
AddGeometryColumn(<nom_du_schema>, <nom_de_la_table>,
<nom_de_la_colonne>, <srid>, <type>,
<dimension>)
Ou, en utilisant le schéma courant :
AddGeometryColumn(<nom_de_la_table>,<nom_de_la_colonne>,
<srid>, <type>, <dimension>)
Exemple 1:
SELECT AddGeometryColumn('public', 'roads_geom', 'geom', 423, 'LINESTRING', 2)
Exemple 2:
SELECT AddGeometryColumn( 'roads_geom', 'geom', 423, 'LINESTRING', 2)
Voici un exemple de code SQL utilisé pour créer une table et ajouter une colonne spatiale (en supposant qu'un SRID de 128 existe déjà) :
CREATE TABLE parks ( PARK_ID int4, PARK_NAME varchar(128), PARK_DATE date, PARK_TYPE varchar(2) );
SELECT AddGeometryColumn('parks', 'park_geom', 128, 'MULTIPOLYGON', 2 );
Voici un autre exemple, utilisant le type générique "geometry" et un SRID indéfinie de valeur -1 :
CREATE TABLE roads ( ROAD_ID int4, ROAD_NAME varchar(128) );
SELECT AddGeometryColumn( 'roads', 'roads_geom', -1, 'GEOMETRY', 3 );
haut de la page | table des matières 4.2.4. Assurer la conformité OpenGIS des géométries
La plupart des fonctions implémentées par la librairie GEOS supposent que vos données géométrique soient valides du point de vue des spécifications "Simple Feature for SQL" de l'OpenGIS. Pour vérifier la validité de vos géométries, vous pouvez utiliser la fonction isValid()
:
gisdb=# select isvalid('LINESTRING(0 0, 1 1)'), isvalid('LINESTRING(0 0,0 0)');
isvalid | isvalid
---------+---------
t | f
Par défaut, PostGIS n'exécute pas la vérification de la validité lors de l'insertion d'objets géométriques, du fait qu'un tel test requière beaucoup de temps processeur pour les géométries complexes, principalement les polygones. Si vous n'avez pas confiance en vos données, vous pouvez manuellement contraindre vos tables en ajoutant une contrainte de validité de la façon suivante :
ALTER TABLE mytable ADD CONSTRAINT geometry_valid_check CHECK (isvalid(the_geom));
Si vous rencontrez un quelconque message d'erreur étrange du style "GEOS Intersection() threw an error!" ou "JTS Intersection() threw an error!" lorsque vous faites appel aux fonctions PostGIS avec des géométries valides, vous avez sans doute trouvé une erreur soit dans PostGIS soit dans une des librairies qu'il utilise, et vous devriez contacter les développeurs de PostGIS pour les en informer. Ceci est aussi vrai si une fonction de PostGIS vous renvoi une géométrie invalid pour une entrée géométriques valide.
Note :
Les géométries strictement conformes à l'OGC ne peuvent pas avoir de valeurs Z ou M. La fonction isValid()
ne considèrera pas les géométries de plus grandes dimensions comme invalide ! L'invocation de AddGeomtryColumn()
ajoutera une contrainte vérifiant les dimensions de la géométrie, il est donc suffisant ici de spécifier 2.
haut de la page | table des matières 4.3. Chargement de données SIG
Une fois que vous avez créer une table spatiale, vous êtes prêt pour ajouter des données SIG à la base de données. Actuellement, il y a deux façons d'insérer les données dans une base PostgreSQL/PostGIS : en utilisant des requête SQL ou en utilisant l'importeur/exporteur de fichiers vecteurs (Shape).
haut de la page | table des matières 4.3.1. Utilisation de code SQL
Si vous pouvez convertir vos données en une représentation textuelle, alors utiliser du code SQL pourrait être la manière la plus simple d'insérer vos données dans PostGIS. Comme avec Oracle et d'autre bases de données SQL, les données peuvent être chargées par le moniteur interactif en utilisant un fichier texte contenant des requêtes de type "INSERT" :
Un fichier d'importation de données (par exemple roads.sql) pourrait ressembler à ceci :
BEGIN;
INSERT INTO ROADS_GEOM (ID,GEOM,NAME ) VALUES (1,GeomFromText('LINESTRING(191232 243118,191108 243242)',-1),'Jeff Rd');
INSERT INTO ROADS_GEOM (ID,GEOM,NAME ) VALUES (2,GeomFromText('LINESTRING(189141 244158,189265 244817)',-1),'Geordie Rd');
INSERT INTO ROADS_GEOM (ID,GEOM,NAME ) VALUES (3,GeomFromText('LINESTRING(192783 228138,192612 229814)',-1),'Paul St');
INSERT INTO ROADS_GEOM (ID,GEOM,NAME ) VALUES (4,GeomFromText('LINESTRING(189412 252431,189631 259122)',-1),'Graeme Ave');
INSERT INTO ROADS_GEOM (ID,GEOM,NAME ) VALUES (5,GeomFromText('LINESTRING(190131 224148,190871 228134)',-1),'Phil Tce');
INSERT INTO ROADS_GEOM (ID,GEOM,NAME ) VALUES (6,GeomFromText('LINESTRING(198231 263418,198213 268322)',-1),'Dave Cres');
COMMIT;
Le fichier de données peut être chargé dans PostgreSQL vraiment facilement en utiliant le moniteur interactif psql
de la façon suivante :
psql -d [database] -f roads.sql
haut de la page | table des matières 4.3.2. Utiliser l'importeur
L'importeur de données shp2pgsql
convertit des fichiers vecteurs (Shape) ESRI en requêtes SQL directement utilisables pour insérer des données dans des bases PostgreSQL/PostGIS. L'importeur possède différents modes opératoires qui se distinguent suivant les options qui lui sont passées en paramètre :
-d | Supprime la table de la base données avant la création de la nouvelle table avec les données du fichier vecteur (Shape). |
-a | Ajoute les données du fichier vecteur dans la table de la base de données. Notez qu'il faut utiliser cette option pour charger plusieurs fichiers, qui doivent contenir les mêmes attributs et les mêmes types de données. |
-c | Crée une nouvelle table et la remplit avec le contenu du fichier vecteur (Shape). C'est le mode par défaut. |
-p | Produit uniquement le code de création des tables, sans ajouter les données. Cela peut être utile lorsque vous avez besoin de séparer complètement les étapes de création de table et celle de son remplissage. |
|
-D | Utilise le format d'export spécial de PostgreSQL pour extraire les données. Cette option peut être combinée avec -a, -c et -d. Ceci est plus rapide pour charger des données que d'utiliser des requêtes au format SQL de type "INSERT". Utilisez ceci pour l'insertion d'une grande quantité de données. |
-s <SRID> | Crée et remplit les tables géométriques avec le SRID spécifié. |
-k | Respecte la syntaxe (casse : majuscules/minuscules) des identifiants (colonne, schéma et attributs). Notez que les attributs dans des fichiers vecteurs sont en majuscules. |
-i | Coercition de tous les entiers en entiers 32 bits standards, ne crée pas de bigints 64 bits, même si la signature de l'en-tête DBF apparait pour le garantir. |
-I | Crée un index GiST sur la colonne géométrique. |
-w | Retour au format WKT, utilisé avec les anciennes versions (0.X) de PostGIS. Notez que cela introduira des dérives de coordonnées et supprimera les valeurs M des fichiers vecteurs. |
-W <encoding> | Spécifie l'encodage des données en entrée (du fichier dbf). Lorsque cette option est utilisée, tous les attributs du dbf sont convertis de l'encodage spécifié en UTF-8. La sortie SQL résultante contiendra une commande SET CLIENT_ENCODING to UTF8 , donc le serveur principal sera capable de reconvertir de l'UTF-8 dans l'encodage choisi dans la configuration de la base de données. |
Notez que les options -a, -c, -d et -p sont mutuellement exclusives.
Une session exemple utilisant l'importeur pour générer un fichier d'importation et le chargement de ce fichier est décrite ci-dessous :
# shp2pgsql shaperoads myschema.roadstable > roads.sql
# psql -d roadsdb -f roads.sql
Une conversion et une importation des données peuvent être faites en une seule étape en utilisant les tubes UNIX :
# shp2pgsql shaperoads myschema.roadstable | psql -d roadsdb
haut de la page | table des matières 4.4. Accéder aux données SIG
Pour accéder aux données de la base vous pouvez soit utiliser le langage SQL soit l'importeur/exporteur de fichiers vecteurs (Shape File). Dans la section traitant du SQL, nous présenterons certains opérateurs disponibles pour comparer les objets géographiques et interroger les tables spatiales.
haut de la page | table des matières 4.4.1. Utilisation du SQL
L'intérêt principal d'insérer des données dans une base de données est de pouvoir utiliser une requête SQL de type SELECT
et de récupérer les champs retournés dans un fichier texte lisible :
db=# SELECT id, ST_AsText(geom) AS geom, name FROM ROADS_GEOM;
id | geom | name
---+-----------------------------------------+-----------
1 | LINESTRING(191232 243118,191108 243242) | Jeff Rd
2 | LINESTRING(189141 244158,189265 244817) | Geordie Rd
3 | LINESTRING(192783 228138,192612 229814) | Paul St
4 | LINESTRING(189412 252431,189631 259122) | Graeme Ave
5 | LINESTRING(190131 224148,190871 228134) | Phil Tce
6 | LINESTRING(198231 263418,198213 268322) | Dave Cres
7 | LINESTRING(218421 284121,224123 241231) | Chris Way
(6 rows)
Parfois certain types de clauses sont nécessaires pour limiter le nombre de champs retournés. Dans le cas de clauses utilisant des attributs standards, utilisez simplement la même syntaxe SQL que celle utilisée pour des tables non spatiales. Dans le cas de clauses mettant en oeuvre des champs spatiaux, les opérateurs suivant sont à utiliser :
&&
: Cet opérateur vérifie si "le cadre limite d'un objet géométrique intersecte celui d'un autre".
~=
: Cet opérateur vérifie si deux objets géométriques sont géographiquement identique. Par exemple, 'POLYGON((0 0,1 1,1 0,0 0))' est géographiquement identique à 'POLYGON((0 0,1 1,1 0,0 0))' (c'est le cas).
=
: Cet opérateur est un peu moins naïf, il vérifie uniquement si les cadres limites des objets géographiques sont les mêmes.
Maintenant, vous pouvez utiliser ces opérateurs dans vos requêtes. Remarquez que lorsque vous utilisez des géométries et des boites dans vos requêtes SQL en ligne de commande, vous devez explicitement spécifier que vous souhaitez créer une géométrie à partir d'une chaine de caractères en utilisant la fonction ST_GeomFromText()
.
Par exemple :
SELECT ID, NAME
FROM ROADS_GEOM
WHERE GEOM ~= ST_GeomFromText('LINESTRING(191232 243118,191108 243242)',-1);
La requête ci-dessus devrait renvoyer un enregistrement unique de la table "ROADS_GEOM" dans lequel l'objet géométrique serait égal à cette valeur.
Lorsque l'opérateur &&
est utilisé, vous pouvez spécifier soit une BOX3D soit un objet géométrique. Lorsque vous spécifiez une GEOMETRY, cependant, son cadre limite est utilisé pour réaliser la comparaison.
SELECT ID, NAME
FROM ROADS_GEOM
WHERE
GEOM && ST_GeomFromText('POLYGON((191232 243117,191232 243119,191234 243117,191232 243117))',-1);
La requête ci-dessus utilisera le cadre limite du polygone pour effectuer la comparaison.
La requête spatiale la plus communément utilisée par une logiciel client, comme par exemple pour des navigateurs de données et des générateurs de cartes sur internet, sera probablement une requête basée sur des cadres limites, pour saisir la valeur du cadre limite d'une carte des données pour affichage. En utilisant un objet de type BOX3D
pour le cadre, une telle requête ressemblerait à cela :
SELECT ST_AsText(GEOM) AS GEOM
FROM ROADS_GEOM
WHERE
GEOM && SetSRID('BOX3D(191232 243117,191232 243119)'::box3d,-1);
Vous remarquerez l'utilisation d'un SRID
, pour spécifier le système de projection de l'objet de type BOX3D
. La valeur -1
est utilisée pour indiquer que le SRID
n'est pas défini.
haut de la page | table des matières 4.4.2. Utilisation de l'exporteur
L'exporteur de table pgsql2shp
se connecte directement à la base de données et convertit une table (potentiellement définie par une requête) en fichier vecteur (shapefile). La syntaxe de base est :
pgsql2shp [<options>] <database> [<schema>.]<table>
pgsql2shp [<options>] <database> <query>
Les options en ligne de commande sont les suivants :
-f <nom_de_fichier> | Écrit le résultat dans le fichier spécifié. |
-h <hôtet> | Le nom du serveur de base de données auquel se connecter. |
-p <port> | Le port utilisé pour se connecter au serveur. |
-P <mot_de_passe> | Le mot de passe à utiliser lors de la connection au serveur. |
-u <utilisateur> | Le nom d'utilisateur à utiliser lors de la connection au serveur. |
-g <colonne géometrique> | Dans le cas de tables avec des colonnes géométriques multiples, la colonne géométrique à utiliser lors de la rédaction du fichier vecteur (shapefile). |
-b | Utilise un curseur binaire. Cela rend l'opération d'extraction plus rapide, mais ne fonctionnera pas si un attribut non-géométrique dans la table n'a pas de conversion en texte possible. |
-r | mode raw. Ne supprime pas le champ gid, ou échappe les noms de colonnes. |
-d | Pour une compatibilité en arrière : crée un fichier vecteur en 3 dimensions lorsque l'on exporte à partir de vieilles versions (pre-1.0.0) de bases de données PostGIS (par défaut il crée des fichiers vecteurs en 2 dimensions dans ce cas). À partir des versions 1.0.0 et supérieures de PostGIS, les dimensions sont complètement encodées. |
haut de la page | table des matières 4.5. Création d'index
Les index rendent possible l'utilisation de base de données spatiales avec de grandes quantités de données. Sans indexation, chaque recherche de propriété pourrait requérir un "parcours séquentiel" de chaque enregistrement de la base de données. L'indexation rend plus rapide les recherches en organisant les données dans un arbre de recherche qui peut être parcouru plus rapidement afin de trouver un enregistrement particulier. Par défaut PostgreSQL supporte trois type d'indexes : les arbres B, les arbres R et les arbre de recherche généralisés (GiST).
- Les arbres B sont utilisés pour les données qui peuvent être ordonnés sur un axes ; par exemple, les nombres, les lettres, les dates. Les données SIG ne peuvent pas rationnellement être ordonnées de cette manière (qui est plus grand, (0,0) ou (0,1) ou (1,0) ?) donc les indexation avec des arbres B n'est pas utile pour nous.
- Les arbres R répartissent les données en rectangles, et sous-rectangles, et sous-sous rectangles, etc. Les arbres R sont utilisés par certaine bases de données spatiales pour indexer les données SIG, mais l'implémentation des arbres R dans PostgreSQL n'est pas aussi robust que l'implémentation des GiST.
- Les arbres de recherches généralisés (GiST) répartissent les données dans des "les choses à coté", "les choses qui couvrent", "les choses qui sont incluses" et peuvent être utilisés pour un grand nombre de type de données, et notamment les données SIG. PostGIS utilise un arbre R implémenté au dessus du GiST pour indexer les données SIG.
haut de la page | table des matières 4.5.1. Les index GiST
GiST signifie "arbre de recherche généralisé" et est une forme générique d'indexation. En plus pour l'indexation GiST, GiST est utilisé pour accélérer les recherches de tout type de données irrégulières (tableau d'entier, données spectrales, etc) qui ne sont pas utilisables avec l'indexation normale par arbre B.
Une fois que les tables de données SIG dépassent quelques milliers d'enregistrements, vous voudrez créer des index pour accélérer les recherches spatiales des données (à moins que vos recherches soient basées sur des attributs, auquel cas vous devrez créer des index normaux sur les champs de ces attributs).
La syntaxe pour créer un index GiST sur une colonne géométrique est la suivante :
CREATE INDEX [nom_de_l_index ON [nom_de_la_table
USING GIST ( [champ_géographique] GIST_GEOMETRY_OPS );
Créer un index spatial est un calcul informatique important : sur les tables d'environ un million d'enregistrements, sur une machine Solaris à 300MHz, nous avons trouvé que la création d'un index GiST prend environ une heure. Après avoir créer un index, il est important de forcer PostgreSQL à collecter les statistiques sur les tables, qui sont utilisées pour optimiser les planifications de requêtes :
VACUUM ANALYZE [table_name] [column_name];
-- Ceci n'est nécessaire que pour les installations de PostgreSQL 7.4 et précédentes :
SELECT UPDATE_GEOMETRY_STATS([table_name], [column_name]);
Dans PotgreSQL, les index GiST ont deux avantages par rapport aux arbres R. Premièrement, les arbres de recherches généralisées acceptent les valeurs null, ce qui signifie qu'ils peuvent indexer des colonnes incluant des valeurs null. Deuxièmement, les arbre de recherches généralisées supportent le concept de "déperdition" qui est important lorsqu'on utilise des objets SIG d'une taille supérieur à la taille de 8K des pages de PostgreSQL. La "déperdition" permet à PostgreSQL de stocker uniquement les parties "importantes" d'un objet dans un index - dans le cas d'objets SIG, uniquement le cadre limite. Les objets SIG plus larges que 8K impliquent que le processus de création des arbres R échouera.
haut de la page | table des matières 4.5.2. Utilisation des index
Habituellement, les index accélèrent l'accès aux données de façon transparente : une fois les index créés, le planificateur de requêtes décide de manière transparente quand utiliser l'index pour accélérer le plan de requête. Hélas, le planificateur de requête de PostgreSQL n'optimise pas bien l'utilisation d'index GiST, donc parfois les recherches qui devraient utiliser les index spatiaux par défaut au lieu d'un parcours séquentiel sur la table entière ne sont pas utilisés.
Si vous constatez que vos index spatiaux ne sont pas utilisés (ou vos index sur les champs, par exemple) il y a quelques "trucs" que vous pouvez tenter :
- Premièrement, assurez vous que les statistiques sont bien au courant du nombre et des distributions de valeurs dans une table, pour fournir de meilleures informations au planificateur de requêtes afin qu'il soit apte à prendre la décision d'utiliser ou non l'index. Pour les installations de PostgreSQL 7.4 et inférieur ceci est fait en exécutant :
update_geometry_stats([nom_de_la_table, nom_de_colonne])
(calcul la distribution) et VACUUM ANALYZE [nom_de_la_table] [nom_de_colonne]
(calcul le nombre de valeurs). À partir de PostgreSQL 8.0, exécuter VACUUM ANALYZE
suffit pour effectuer les deux opérations. De toute manière, vous pouvez régulièrement nettoyer votre base de données - plusieurs administrateurs de base de données PostgreSQL exécutent dans leur crontab un nettoyage via VACUUM
.
- Si le nettoyage ne fonctionne pas, vous pouvez obliger le planificateur de requêtes à utiliser l'index en utilisant la commande :
SET ENABLE_SEQSCAN=OFF
. Vous devez utiliser cette commande avec parcimonie, et uniquement des requêtes spatialement indexées : plus généralement, le planificateur de requêtes connait mieux que vous lorsqu'il faut utiliser normalement l'arbre B. Une fois que vous avez effectué votre requête, vous pouvez réaffecter la valeur initiale de ENABLE_SEQSCAN
, de sorte que les autres requêtes utiliseront normalement le planificateur.
Note :
Comme pour la version 0.6, il n'est pas nécessaire de forcer le planificateur à utiliser l'index avec ENABLE_SEQSCAN
.
Si vous constatez que le planificateur a tort à propos du cout d'un parcours séquentiel par rapport à l'index, essayez de réduire la valeur du paramètre random_page_cost
dans votre postgresql.conf
ou utilisez la commande SET random_page_cost=#
. La valeur par défaut pour ce paramètre est 4, essayez d'y attribuer les valeurs 1 ou 2. Décrémenter cette valeur rend le planificateur plus enclin à utiliser les parcours via l'index.
haut de la page | table des matières 4.6. Requêtes complexes
La raison d'être des fonctionnalités spatiales des base de données est de vous permettre d'effectuer des requêtes qui requièrent habituellement des outils SIG bureautiques. Utiliser PostGIS de manière efficace nécessite de connaitre qu'elles sont les fonctions spatiales disponibles et de s'assurer que les indexes appropriés sont en place pour obtenir de bonne performances.
haut de la page | table des matières 4.6.1. Tirer avantage des indexes.
Lorsque vous construisez une requête il est important de se souvenir que seuls les opérateurs du cadre-limite comme &&
tirent avantage des indexes spatiaux GIST. Les fonctions comme distance()
ne peuvent pas utiliser les indexes pour optimiser leur opérations. Par exemple, la requête suivante pourrait être légèrement lente sur une grosse table :
SELECT the_geom FROM geom_table WHERE distance( the_geom, GeomFromText( 'POINT(100000 200000)', -1 ) ) < 100
Cette requête sélectionne toutes les géométries de
geom_table
qui sont dans un rayon de 100 unités du point (100000, 200000). Elle est lente parce qu'elle calcule la distance entre chaque point de la table et le point que nous avons spécifié, par exemple un calcul de
distance()
pour chaque enregistrement de la table. Nous pouvons éviter cela en utilisant l'opérateur
&&
pour réduire le nombre de distance requit :
SELECT the_geom FROM geom_table
WHERE the_geom && 'BOX3D(90900 190900, 100100 200100)'::box3d
AND distance( the_geom, GeomFromText( 'POINT(100000 200000)', -1 ) ) < 100
Cette requête sélectionne les même géométries, mais il le fait de manière plus efficace. Supposons qu'il existe un indexe GiST sur
the_geom
, le planificateur de requêtes constatera qu'il peut utiliser l'indexe pour réduire le nombre de ligne avant de calculer le résultat de la fonction
distance()
. Notez que la géométrie
BOX3D
qui est utilisé dans l'opération
&&
est un cadre carré de 200 unités centré sur le point original - c'est notre "cadre de requête". L'opérateur
&&
utilise l'indexe pour réduire rapidement l'ensemble résultant aux géométries qui ont un cadre limite qui recouvre le "cadre de requête". En supposant que notre "cadre de requête" est plus petit que l'extension de la totalité de la table, cela réduira considérablement le nombre de calculs de distance qui devra être effectué.
depuis PostGIS 1.3.0, la plupart des fonctions relationnelles, à l'exception de ST_Disjoint
and ST_Relate
, utilisent implicitement l'opérateur de superposition du cadre limite.
haut de la page | table des matières 4.6.2. Exemple de SQL spatial
Les exemples de cette section utiliseront deux tables, une table de routes linéaires, et une table de limite polygonales des municipalités. La définition pour la table bc_routes est la suivante :
Column | Type | Description
---------+-------------------+-------------------
gid | integer | Unique ID
name | character varying | Road Name
the_geom | geometry | Location Geometry (Linestring)
La définition pour la table bc_minicipalitees est la suivante :
Column | Type | Description
-----------+-------------------+-------------------
gid | integer | Unique ID
code | integer | Unique ID
name | character varying | City / Town Name
the_geom | geometry | Location Geometry (Polygon)
haut de la page | table des matières 4.6.2.1. Quelle est la longueur totale en kilomètres de toutes les routes ?
Vous pouvez répondre à cette question avec une requête SQL simple :
postgis=# SELECT sum(length(the_geom))/1000 AS longueur_routes_en_km FROM bc_routes :
longueur_routes_en_km
------------------
70842.1243039643
(1 row)
haut de la page | table des matières 4.6.2.2. Quelle est l'aire en hectare de la ville Prince George ?
Cette requête combine une condition attributaire (sur le nom de la municipalité) avec un calcul spatial (de l'aire) :
postgis=# SELECT area(the_geom)/10000 AS hectares FROM bc_municipalite WHERE name = 'PRINCE GEORGE';
hectares
------------------
32657.9103824927
(1 row)
haut de la page | table des matières 4.6.2.3. Quelle est la plus grande municipalité (aire) de la province ?
Cette requête utilise une mesure spatiale comme condition. Il y a plusieurs manières d'approcher ce problème, mais la plus efficace est la suivante :
postgis=# SELECT name, area(the_geom)/10000 AS hectares
FROM bc_municipalite
ORDER BY hectares DESC LIMIT 1;
name | hectares
---------------+-----------------
TUMBLER RIDGE | 155020.02556131
(1 row)
Vous remarquerez que pour répondre à cette question nous devons calculer l'aire de tous les polygones. Si nous faisons souvent cela, il serait judicieux d'ajouter une colonne "aire" à la table que nous pourrions alors indexer pour plus de performance. En ordonnant le résultat par ordre décroissant, et en utilisant la commende LIMIT
de PostgreSQL nous pouvons aisément récupérer la plus grande valeur sans avoir à utiliser de fonction d'agrégation comme max()
.
haut de la page | table des matières 4.6.2.4. Quelle est la longueur des routes totalement contenues dans chaque municipalités ?
Ceci est un exemple de "jointure spatiale', parce que nous utilisons les données de deux tables (en faisant une jointure) mais en utilisant une condition d'interaction spatiale ("contenue") comme condition de jointure au lieu d'utiliser l'approche relationnelle habituelle de jointure sur une clef commune :
postgis=# SELECT m.name, sum(length(r.the_geom))/1000 as roads_km
FROM bc_roads AS r,bc_municipality AS m
WHERE r.the_geom && m.the_geom
AND contains(m.the_geom,r.the_geom)
GROUP BY m.name
ORDER BY roads_km;
name | roads_km
----------------------------+------------------
SURREY | 1539.47553551242
VANCOUVER | 1450.33093486576
LANGLEY DISTRICT | 833.793392535662
BURNABY | 773.769091404338
PRINCE GEORGE | 694.37554369147
...
Cette requête dure un moment, parce que chaque route de la table est disponible dans le résultat final (environ 250K routes pour notre table d'exemple). Pour des couvertures plus petites (quelques milliers ou centaines d'enregistrements) la réponse peut être très rapide.
haut de la page | table des matières 4.6.2.5. Créer une nouvelle table contenant toutes les routes de la ville de Prince George.
Ceci est un exemple de "couverture", qui extrait les données de deux tables et retourne une nouvelle table qui contient l'ensemble des résultantes incluses ou partiellement coupées. Contrairement à la "jointure spatiale" présentée précédemment, cette requête crée de nouvelles géométries. Une couverture est comme une jointure spatiale turbo-cached, et est utile pour un travail d'analyse plus précis :
postgis=# CREATE TABLE pg_roads as
SELECT intersection(r.the_geom, m.the_geom) AS intersection_geom,
length(r.the_geom) AS rd_orig_length,
r.*
FROM bc_roads AS r, bc_municipality AS m
WHERE r.the_geom && m.the_geom
AND intersects(r.the_geom, m.the_geom)
AND m.name = 'PRINCE GEORGE';
haut de la page | table des matières 4.6.2.6. Quelle est la longueur en kilomètre de "Douglas St" à Victoria ?
postgis=# SELECT gid, name, area(the_geom) AS area
FROM bc_municipality
WHERE nrings(the_geom) > 1
ORDER BY area DESC LIMIT 1;
gid | name | area
-----+--------------+------------------
12 | SPALLUMCHEEN | 257374619.430216
(1 row)
haut de la page | table des matières 4.7. Utilisation de Mapserver
Minnesota Mapserver est un serveur cartographique Internet qui se conforme aux spécifications "Web Mapping Server" de l'OpenGIS.
haut de la page | table des matières 4.7.1. Utilisation de base
Pour utiliser PostGIS avec Mapserver vous aurez besoin de savoir comment configurer Mapserver, ce qui dépasse le cadre de cete documentation. Cette section va couvrir les particularités d'une utilisation avec Postgis et les détails de la configuration.
Pour utiliser PostGIS avec Mapserver, vous aurez besoin de :
- La version 0.6 ou supérieure de PostGIS.
- La version 3.5 ou supérieure de Mapserver.
Mapserver accède aux données PostgreSQL/PostGIS comme n'importe quel autre client PostgreSQL - c'est à dire en utilisant la libpq. Cela signifie que Mapserver peut être installé sur chaque machines ayant un accès réseau vers un serveur PostGIS, temps que le système possède la libraire client de PostgreSQL (libpq).
- Compilez et installez Mapserver, avec les supports qui vous souhaitez activer, incluant l'option de configuration : "--with-postgis".
- Dans votre fichier map de Mpaserver, ajouté une couche PostGIS. Par exemple :
LAYER
CONNECTIONTYPE postgis
NAME "widehighways"
# Connect to a remote spatial database
CONNECTION "user=dbuser dbname=gisdatabase host=bigserver"
# Get the lines from the 'geom' column of the 'roads' table
DATA "geom from roads"
STATUS ON
TYPE LINE
# Of the lines in the extents, only render the wide highways
FILTER "type = 'highway' and numlanes >= 4"
CLASS
# Make the superhighways brighter and 2 pixels wide
EXPRESSION ([numlanes] >= 6)
COLOR 255 22 22
SYMBOL "solid"
SIZE 2
END
CLASS
# All the rest are darker and only 1 pixel wide
EXPRESSION ([numlanes] < 6)
COLOR 205 92 82
END
END
Dans l'exemple ci-dessus, les directives spécifiques à PostGIS sont les suivantes :
CONNECTIONTYPE
Pour les couches PostGIS, cela sera toujours "postgis".
CONNECTION
La connection à la base de données est gouvernée par "la chaine de charatères de connection" ("connection string") qui est contituée d'un ensemble de couples nom/valeur comme ceci (avec la valeur par défaut entre < >) :
user=<nom_d_utilisateur> password=<mot_de_passe> dbname=<nom_de_la_base_de_données> hostname=<serveur> port=<5432>
Une chaine de charactères de connection vide reste valide, et chacun des couples nom/valeur peut être omis. Au minimum vous aurez généralement besoin de spécifier le nom de la base de données et le nom d'utilisateur avec lequel vous souhaitez vous connecter.
DATA
La forme de ce paramètre est : "<colonne> from <nom_de_la_table>" où la colonne est une colonne spatiale qui doit être affiché sur la carte.
FILTER
Le filtre doit être une chaîne de charactères SQL valide correspondant à la logique normale suivant le mot clef "WHERE" dans les requêtes SQL. Donc, par exemple, pour afficher uniquement les routes ayant 6 voies ou plus, utilisé le filtre "nombre_de_voies >= 6".
- Dans votre base de données spatiale, assurez vous que vous avez des indexes spatiaux (GiST) pour chaque couches que vous souhaitez afficher.
CREATE INDEX [nom_de_l_index]
ON [nom_de_la_table]
USING GIST ( [colonne_géometrique] GIST_GEOMETRY_OPS );
- Si vous allez interroger vos couches en utilisant Mpaserver vous aurez aussi besoin d'un "index oid".
Mapserver requière des indentifiants uniques pour chaque enregistrement spatial lorsque vous souhaitez effetuer des interrogations, et le module PostGIS de Mapserver utilise les valeurs d'oid de PostgreSQL pour fournir ces identifiants uniques. Cela implique comme effet de bord que si vous souhaitez effectuer des accès aléatoires rapides aux enregistrements durant les requêtes, un index sur les oid est necessaires.
Pour construire un tel index, utilisez la requête SQL suivante :
CREATE INDEX [nom_de_l_index] ON [nom_de_la_table] ( oid );
haut de la page | table des matières 4.7.2. Questions fréquemment posées
4.7.2.1. Lorsque j'utilise une EXPRESSION dans ma map, la condition ne retourne jamais vrai, même si elle devrait.
Contrairement aux fichiers vecteurs (shapefile), les noms de champs PostGIS doivent être référencés dans EXPRESSIONS en utilisant des lettres en minuscule.
EXPRESSION ([nombre_de_voies] >= 6)
haut de la page | table des matières 4.7.2.2. Le FILTER que j'utilise pour mon fichier vecteur ne fonctionne pas pour ma table PostGIS contenant les mêmes données.
Contrairement aux fichiers vecteurs (shapefile), les filtres pour les couches PostGIS utilisent la syntaxe SQL (ils sont concaténés à l'état SQL que le connecteur PostGIS génère pour afficher les couches dans Mapserver).
FILTER "type = 'autoroute' and nombre_de_voies >= 4"
haut de la page | table des matières 4.7.2.3. Ma couche PostGIS se dessine plus doucement que mon fichier vecteur, est-ce normal?
En général, les couches PostGIS sont 10 % plus lentes que les couches équivalentes en fichier vecteurs, ceci est due au temps qui incombe à la connection au serveur de base de données, les transformations et la transmission des données entre la base et Mapserver.
Si vous avez des problèmes de performance d'affichage, cela est généralement lié au fait que vous n'avez pas créé les indexes spatiaux pour vos tables.
postgis# CREATE INDEX geotable_gix ON geotable USING GIST ( geocolumn );
postgis# SELECT update_geometry_stats(); -- Pour PGSQL < 8.0
postgis# VACUUM ANALYZE; -- Pour PGSQL >= 8.0
haut de la page | table des matières 4.7.2.4. Mes couches PostGIS s'affichent correctement, mais les requêtes sont vraiment lentes. Que se passe-t-il ?
Pour que les requêtes soient rapides, vous devez avoir une clef unique pour vos tables spatiales et un index sur cette clef unique.
Vous pouvez spécifier quelle clef unique doit être utilisée par Mapserver, en utilisant la clause : USING UNIQUE
dans votre ligne DATA
:
DATA "the_geom FROM geotable USING UNIQUE gid"
Si votre table n'a pas de colonne explicitement unique, vous pouvez "faire semblant" de rendre une colonne unique en utilisant la colonne PostgreSQL "oid" comme colonne unique. "oid" est la colonne unique par défaut si vous n'en déclarez pas une, donc pour améliorer le temps d'exécution de vos requêtes vous devez créer des indexes sur les valeurs oid de vos tables spatiales.
postgis# CREATE INDEX geotable_oid_idx ON geotable (oid);
haut de la page | table des matières 4.7.3. Utilisation avancée
La clause pseudo-SQL USING
est utilisée afin d'ajouter des informations pour aider Mapserver à comprendre les résultats de plusieurs requêtes complexes. Plus précisément, lorsqu'une vue ou une sous-requête de sélection est utilisée comme table source (le terme à la droite du FROM
dans la définition de DATA
) il est plus difficile pour Mapserver de déterminer automatiquement un identifiant unique pour chaque tuple et le SRID pour la table. La clause USING
peut fournir à Mapserver ces deux types d'informations :
DATA "the_geom FROM (SELECT table1.the_geom AS the_geom, table1.oid AS oid, table2.data AS data
FROM table1 LEFT JOIN table2 ON table1.id = table2.id) AS new_table USING UNIQUE oid USING SRID=-1"
USING UNIQUE <idunique>
Mapserver requière un identifiant unique pour chaque tuple dans le but d'identifier une ligne lorsque l'on effectue des interrogations de la carte. Normalement, il devrait utiliser l'oid comme identifiant unique, mais les vues et les sous-requêtes de sélection n'ont pas obligatoirement cette colonne oid. Si vous souhaitez utiliser les fonctionnalités d'interrogation de Mapserver, vous aurez besoin d'ajouter une colonne unique à vos vues ou vos sous-requêtes de sélection, et déclarer ceci en utilisant : USING UNIQUE
. Pour ce faire, vous pouvez, par exemple, explicitement sélectionner une des valeurs d'oid de la table, ou l'une des autres colonnes pour laquelle vous garantissez l'unicité dans l'ensemble résultant.
L'état USING
peut aussi être utile pour de simples état DATA
, si vous effectuez des interrogations de la carte. Il était jadis recommandé d'ajouter un indexe sur la colonne oid des tables utilisées dans les couches interrogeables, dans le but d'accélérer les requêtes de la carte. Cependant, avec la clause USING
, il est possible de spécifier à Mapserver d'utiliser la clef primaire de votre table comme identifiant pour interroger la carte, il n'est ainsi plus nécessaire d'avoir un indexe supplémentaire.
Note :
"Interroger une carte" est l'action qui consiste à cliquer sur la carte pour demander les informations relatives à la zone géographique sélectionnée. Ne confondez pas "interrogation de carte" avec requête SQL dans la définition de DATA
.
USING SRID=<srid>
PostGIS a besoin de connaitre quel système de référence spatial doit être utilisé par les géométries afin de retourner correctement les données à Mapserver. Normalement il est possible de trouver ces informations dans la table "geometry_columns" dans une base de données PostGIS, cependant, il n'est pas possible pour les tables qui ont été créées à la volée comme des sous-requêtes de sélection ou des vues. Donc l'option USING SRID=
vous permet de spécifier le SRID correspondant à vos données dans la définition de DATA
.
Attention :
Le parser pour les couches PostGIS de Mapserver est légérement primitif et est sensible à la casse dans certaines parties. Faites attention à ce que tous les mots clefs SQL et toutes les clauses USING
soient en lettres majuscules, et que vos clauses USING UNIQUE
précèdent bien vos clauses USING SRID
.
haut de la page | table des matières 4.7.4. Exemples
Commençons avec un exemple simple et qui nous servira de base pour la suite. Considérons la définition de couche Mapserver suivante :
LAYER
CONNECTIONTYPE postgis
NAME "routes"
CONNECTION "user=lutilisateur password=lemotdepasse dbname=labase host=leserveur"
DATA "the_geom FROM routes"
STATUS ON
TYPE LINE
CLASS
COLOR 0 0 0
END
END
Cette couche affichera toutes les géométries de la table routes comme des lignes noires.
Maintenant, supposons que nous voulions uniquement afficher les autoroutes lorsque nous zoomons au moins à une échelle de 1:100000, les deux prochaines couches permettent cela :
LAYER
CONNECTION "user=lutilisation password=lemotdepasse dbname=labase host=leserveur"
DATA "the_geom FROM routes"
MINSCALE 100000
STATUS ON
TYPE LINE
FILTER "type_de_route = 'autotourte'"
CLASS
COLOR 0 0 0
END
END
LAYER
CONNECTION "user=lutilisateur password=lemotdepasse dbname=labase host=leserveur"
DATA "the_geom FROM routes"
MAXSCALE 100000
STATUS ON
TYPE LINE
CLASSITEM type_de_route
CLASS
EXPRESSION "autoroute"
SIZE 2
COLOR 255 0 0
END
CLASS
COLOR 0 0 0
END
END
La première couche est utilisée lorsque l'échelle est plus grande que 1:100000, et affiche uniquement des lignes noires pour les routes de type "autoroute". L'option FILTER
entraine que seules les routes de type "autoroute" doivent être affichées.
La seconde couche est utilisée lorsque l'échelle est plus petite que 1:100000, et affichera les autoroutes comme des lignes rouges à double-profondeurs, et les autre routes comme des lignes noires standards.
Donc, nous avons fait un couple de choses intéressantes en utilisant uniquement les fonctionnalités de Mapserver, mais nos états SQL dans les définitions de DATA
sont restées simples. Supposons que le nom des routes soit stocké dans une autre table (pour une raison quelconque) et que nous souhaitions faire une jointure pour récupérer et étiqueter nos routes.
LAYER
CONNECTION "user=lutilisateur password=lemotdepasse dbname=labase host=leserveur"
DATA "the_geom FROM (SELECT routes.oid AS oid, routes.the_geom AS the_geom, nom_des_routes.nom as nom
FROM routes LEFT JOIN nom_des_routes ON routes.id_nom_de_routes = nom_des_routes.id_nom_de_routes) AS routes_nommées
USING UNIQUE oid USING SRID=-1"
MAXSCALE 20000
STATUS ON
TYPE ANNOTATION
LABELITEM nom
CLASS
LABEL
ANGLE auto
SIZE 8
COLOR 0 192 0
TYPE truetype
FONT arial
END
END
END
Cette couche d'annotation ajoute des étiquettes vertes à toutes les routes lorsque l'échelle atteint 1:20000 ou moins. Cela montre aussi comment utiliser les jointures SQL dans une définition de DATA
.
haut de la page | table des matières 4.8. Clients Java (JDBC)
Les clients Java peuvent accéder aux objets géométriques de PostGIS dans une base de données PostgreSQL soit directement via les représentations textuelles ou en utilisant les objets de l'extension JDBC distribuée avec PostGIS. Dans le but d'utiliser les objets de l'extension, le fichier "postgis.jar" doit être ajouté à votre CLASSPATH ainsi que le driver JDBC de PostgreSQL "postgresql.jar".
import java.sql.*;
import java.util.*;
import java.lang.*;
import org.postgis.*;
public class JavaGIS {
public static void main(String[] args)
{
java.sql.Connection conn;
try
{
/*
* Chargement du pilote JDBC et établissement d'une connection.
*/
Class.forName("org.postgresql.Driver");
String url = "jdbc:postgresql://localhost:5432/database";
conn = DriverManager.getConnection(url, "postgres", "");
/*
* Ajout du type géométrique à la connection. Notez que vous devez effectuer
* une convertion de type pour la connection avant de faire appèle à la méthode
* addDataType().
*/
((org.postgresql.Connection)conn).addDataType("geometry","org.postgis.PGgeometry");
((org.postgresql.Connection)conn).addDataType("box3d","org.postgis.PGbox3d");
/*
* Crée un état et exécute la requête de selection.
*/
Statement s = conn.createStatement();
ResultSet r = s.executeQuery("select AsText(geom) as geom,id from geomtable");
while( r.next() )
{
/*
* Récupération de la géométrie comme un objet puis convertion de type en
* vers le type geometry. Affichage des résultats.
*/
PGgeometry geom = (PGgeometry)r.getObject(1);
int id = r.getInt(2);
System.out.println("Row " + id + ":");
System.out.println(geom.toString());
}
s.close();
conn.close();
}
catch( Exception e )
{
e.printStackTrace();
}
}
}
L'objet "PGgeometry" est un objet de transition qui contient un objet géométrique à topologie spécifique (sous-classe de la classe abstraite "Geometry") dépendant du type : Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon.
PGgeometry geom = (PGgeometry)r.getObject(1);
if( geom.getType() = Geometry.POLYGON )
{
Polygon pl = (Polygon)geom.getGeometry();
for( int r = 0; r < pl.numRings(); r++ )
{
LinearRing rng = pl.getRing(r);
System.out.println("Ring: " + r);
for( int p = 0; p < rng.numPoints(); p++ )
{
Point pt = rng.getPoint(p);
System.out.println("Point: " + p);
System.out.println(pt.toString());
}
}
}
La JavaDoc fournit, pour les objets de l'extension, une référence pour les diverses méthodes d'accès aux données dans les objets géométriques.
haut de la page | table des matières 4.9. Clients C (libpq)
4.9.1. Curseurs Text
4.9.2. Curseurs Binaires