Académique Documents
Professionnel Documents
Culture Documents
Nous allons supposer dans cette sous-sections que -i Use int4 type for all integer dbf fields.
nous disposons des mêmes sources de données
que celles ci-dessus. Ces dernières cette fois-ci au -I Create a GiST index on the geometry column.
lieux d'être stockées au format sql sont ici stockées
au format .shp. Chaque table est ainsi stockées -w Use wkt format (for postgis-0.x support - drops
dans un fichier .shp - avec les fichiers auxiliaires M - drifts coordinates).
adéquates (.dbf, .shx....).
-N <policy> Specify NULL geometries handling
Note policy (insert,skip,abort)
Les fichiers en question sont disponibles à Avec shp2pgsql, la ligne de commande la plus
http://www.postgis.fr/download/win32/shp.zip. utilisée est
Décompressez ce fichier et double-cliquez sur le
fichier batch import.bat pour les charger dans la shp2pgsql -D -I shapefile nom_table | psql
base. N'hésitez pas à ouvrir pour l'étudier par base_de_donnees
rapport aux explications qui suivent sur
shp2pgsql.exe. SI vous n'avez pas pour le moment où l'option
importé le fichier madatabase.sql (cf. "Chargement
en SQL") ouvrez alors ce fichier et remplacez • -D permet d'importer les données sous
l'option "-dD" en "-D". forme de COPY au lieu de INSERT. Ce qui
est beaucoup plus rapide au niveau de
PostGIS est livré avec un convertisseur l'importation des données
shp2pgsql.exe qui permet d'importer directement - • -I permet de créer automatiquement un
à la volée - les données fournies dans un fichier index spatial pour les données
.shp. Pour de meilleurs informations sur ce géométriques importées
convertisseur, il suffit de saisir • shapefile est le chemin d'accès complet
vers le shapefile
shp2pgsql --help • nom_table est le nom que vous
souhaiteriez donner à votre table
qui vous renverra en sortie
1.3. Question: Qu'elle est l'étendue
shp2pgsql: illegal option -- - géographique/emprise de la table
RCSID: $Id: shp2pgsql.c,v 1.104 2005/11/01 communes_lr? - Extent() -
09:25:47 strk Exp $
USAGE: shp2pgsql [<options>] <shapefile> • Par définiton, je rappelle que l'étendue
[<schema>.]<table> géographique d'un objet spatial dans une
base de données est la plus petit fenêtre
OPTIONS: (=rectangle) qui le contienne. Ce dernier
-s <srid> Set the SRID field. If not specified it est défini par le quadruplet
defaults to -1. (Xmin,Ymin,Xmax,Ymax) . (Xmin,Ymin)
(respectivement (Xmax,Ymax)) est le
(-d|a|c|p) These are mutually exclusive options: sommet inférieur gauche (respectivement
-d Drops the table , then recreates it and le sommet supérieur droit) du rectangle
populates it with current shape file data. dans tout système de projection orienté
-a Appends shape file into current table, must de gauche à droite horizontalement et de
be exactly the same table schema. bas en haut vertivalement.
-c Creates a new table and populates it, this is • Pour connâitre ce quadruplet, la requête
the default if you do not specify any options. suivante
-p Prepare mode, only creates the table • SELECT Xmin(foo.extent),
• Ymin(foo.extent),
-g <geometry_column> Specify the name of the • Xmax(foo.extent),
geometry column • Ymax(foo.extent)
1
• FROM (SELECT Extent(the_geom) FROM select version()
communes_lr) AS foo
qui nous renvoit
nous renvoit comme résultat
version
• xmin | ymin | xmax | --------------------------------------------------------------------
ymax
PostgreSQL 8.2.1 on i686-pc-mingw32, compiled
• --------+-------------+--------
+-------------
by GCC gcc.exe (GCC) 3.4.2 (mingw-special)
• 547293 | 1703209.875 | 801423 |
(1 ligne)
1997767.125
• (1 row) On peut aussi utiliser la requête suivante
• Ce dernier implique donc que tous les
objets de la colonne géométrique SHOW server_version
the_geom sont contenus dans le
quadruplet ci-dessus obtenu. qui nous renvoit
Note
pg_config --version
La requête suivante
SHOW data_directory
data_directory
----------------------------------------
C:/PostgreSQL/8.2.1/data
(1 ligne)
Note
1.6. Question-Pratique: Qui sont les utilisateurs
Connaître l'étendue géographique peut s'avérer
de PostgreSQL?
utile, notamment avec Mapserver dont les
fichiers mapfiles possèdent un paramètre EXTENT
qui correspond à l'étendue géogpraphique. Ici il Je ne fais pas ici de distinction entre les super-
s'agira de fournir ce quadruplet. Ce que on utilisateurs et les utilisateurs courants de
appelle étendue géographique est aussi ce PostgreSQL. En un mot, je ne m'occuperais pas ici
qu'on appelle emprise en SIG classique des droits attibués (création de base, ajout
d'utilisateur etc...). Pour simplifier, on dira que la
1.4. Question-Pratique: Qu'elle est la version de requête est
PostgreSQL?
select usename from pg_user order by usename
Il suffit pour cela d'utiliser la fonction interne de
PostgreSQL: Version() qui nous renvoit
2
usename cela se fait en faisant la requête suivante
----------
david SELECT pg_database.datname
keizer FROM pg_database, pg_user
postgres WHERE pg_database.datdba =
(3 lignes) pg_user.usesysid
AND pg_database.datname not
On obtient de meilleurs informations en faisant LIKE 'template%' order by datname
directement depuis MinGW ou DOS la commande
suivante: qui ici renvoit
postgis_full_version nom_table
-------------------------------------------------------------------- ----------------
POSTGIS="1.2.0" GEOS="2.2.3-CAPI-1.1.1" buildings
PROJ="Rel. 4.5.0, 22 Oct 2006" USE_STATS great_roads
(1 ligne) mapserver_desc
parcs
Ce qui prouve bien que PostGIS 1.2.0, Geos 2.2.3 personnes
et Proj 4.5.0 ont bien compilés. rivers
small_roads
Note (7 rows)
Il existe aussi d'autres fonctions qui permettent Le listing des tables peut facilement être obtenu en
d'obtenir des informations: postgis_geos_version(), tapant simpelement '\dt' dans psql le moniteur
postgis_proj_version(),...Vous obtiendrez d'autres interactif de PostgreSQL.
fonctions en faisant directement depuis psql:
Note
\df *postgis*
Je pars ici du principe que toutes les tables sont
\df est le raccourci de psql pour obtenir le détail sur contenues dans un même schéma et soient
des fonctions contenus sur un même espace logique de
PostgreSQL. Mais si vous êtes sûr que toutes vos
1.8. Question-Pratique: Quel est le listing des tables sont dans le même schéma, vous pouvez
bases de PostreSQL? par exemple exploiter la requête
3
select tablename as nom_table from pg_tables
where schemaname='public' ADD [ COLUMN ] colonne type
and tablename not in [ contrainte_colonne [ ... ] ]
('spatial_ref_sys','geometry_columns') order by DROP [ COLUMN ] colonne [ RESTRICT |
tablename; CASCADE ]
ALTER [ COLUMN ] colonne TYPE type
1.10. Question-Pratique: Utiliser une vue pour [ USING expression ]
simplifier la recherche du listing des ALTER [ COLUMN ] colonne SET DEFAULT
tables. expression
ALTER [ COLUMN ] colonne DROP DEFAULT
PostgreSQL offre un concept fort appréciable ALTER [ COLUMN ] colonne { SET | DROP }
concernant les SGDBR, celui des vues. Les vues NOT NULL
permettent parfois de se simplifier la vie avec des ALTER [ COLUMN ] colonne SET STATISTICS
requêtes parfois bien longue et que l'on ne pourrait integer
pas toujours pouvoir se souvenir. Pour la requête ALTER [ COLUMN ] colonne SET STORAGE
concernant le listing des tables contenues dans { PLAIN | EXTERNAL | EXTENDED | MAIN }
une base de données - vu précédemment - on peut ADD contrainte_table
avoir recours aux vues en créant la la vue suivante DROP CONSTRAINT nom_contrainte
[ RESTRICT | CASCADE ]
create view liste_table as select tablename as DISABLE TRIGGER [ nom_déclencheur | ALL |
nom_table from pg_tables where USER ]
(tablename not like 'pg_%') and (tablename not like ENABLE TRIGGER [ nom_déclencheur | ALL |
'spatial_ref_sys' ) USER ]
and (tablename not like 'sql_%' ) and (tablename CLUSTER ON nom_index
not like 'geom%' ) order by tablename; SET WITHOUT CLUSTER
SET WITHOUT OIDS
On aura alors le listing attendu en faisant OWNER TO nouveau_propriétaire
directement SET TABLESPACE nouvel_espacelogique
Supposons que l'on ne se souvienne plus de la psql -d template1 -c "\h" > memento.sql
synthaxe pour la commande ALTER TABLE. Rien
de plus simple avec psql! Faites précéder votre commande qui redirigera la sortie vers le fichier
commande de \h memento.sql qu'il suffira ensuite d'ouvrir pour
obtenir l'aide attendue.
testgis=\h ALTER TABLE
1.12. Question: Où sont stockées les
qui renverra informations relatives aux données
spatiales (métadonnées) des tables avec
Commande : ALTER TABLE PostGIS? - table geometry_columns -
Description : modifier la définition d'une table
Syntaxe : Ces informations (srid, type, nom de la colonne
ALTER TABLE [ ONLY ] om [ * ] géométrique) sont stockées dans la table
action [, ... ] geometrycolumns. La requête
ALTER TABLE [ ONLY ] nom [ * ]
RENAME [ COLUMN ] colonne TO select * from geometry_columns
nouvelle_colonne
ALTER TABLE nom nous renvoit les informations suivantes
RENAME TO nouveau_nom
ALTER TABLE nom f_table_catalog | f_table_schema | f_table_name |
SET SCHEMA nouveau_schéma f_geometry_column | coord_dimension | srid |
type
où action fait partie de :
4
-----------------+----------------+-------------- CREATE TYPE nom_de_table AS (tablename
+-------------------+-----------------+------+------------ name);
| public | personnes | the_geom
| 2 | -1 | POINT Il est alors possible d'utiliser la fonction suivante
| public | buildings | the_geom
| 2 | -1 | POLYGON CREATE OR REPLACE FUNCTION
| public | small_roads | the_geom diff_geometry_columns() RETURNS SETOF
| 2 | -1 | LINESTRING nom_de_table AS $$
| public | great_roads | the_geom DECLARE
| 2 | -1 | LINESTRING j nom_de_table;
| public | parcs | the_geom BEGIN
| 2 | -1 | POLYGON FOR j IN SELECT tablename AS nom_table
| public | rivers | the_geom FROM pg_tables WHERE tablename NOT IN
| 2 | -1 | POLYGON ( (SELECT f_table_name FROM
(6 rows) geometry_columns) UNION (SELECT
'spatial_ref_sys') UNION (select
Les informations utiles sont 'geometry_columns'))
AND pg_tables.schemaname='public' ORDERBY 1
• f_table_name qui fournit le nom de la table; LOOP
• f_geometry_column qui donne le nom de -- cette syntaxe est nécessaire pour retourner
la colonne géométrique; plusieurs lignes
• srid fournit le srid - identifiant de système RETURN NEXT j;
de projection-; END LOOP;
• type qui fournit le type d'objet contenu dans END;
la table. $$ LANGUAGE plpgsql STABLE;
6
select 1.16. Question: Qui est dans le bâtiment
Srid('010100000000000000008041400000000000 Résidence des Mousquetaires ?
805140'::geometry);
srid La requête suivante
------
-1 select personnes.data as
(1 ligne) personnes_dans_batiment_2 from
personnes,buildings
En mode d'entrée, PostGIS accepte aussi le where
HEXEWKB directement et PostgreSQL le stockera within(personnes.the_geom,buildings.the_geom)
tout simplement en HEXEWKB. Ainsi dans dans and buildings.data = 'Résidence des
une table test dont la structure serait par exemple Mousquetaires';
CREATE TABLE test (..., the_geom GEOMETRY); nous renverra comme réponse
La requête suivante
8
Rue Aristide Briand | LINESTRING(85 1,85 En fonction de leur convexité/concavité, les
135) | 2 POLYGON peuvent avoir leur centre situé à
(3 lignes) l'extérieur. C'est ce qui se passe ici par exemple
pour le bâtiment "Bibliothèque Victor Hugo". Ce qui
1.19. Question: Dans la table great_roads, quels nous amène à la question suivante
sont les premier et dernier point de la
Rue Paul Valéry? - StartPoint(), 1.21. Question: Comment garantir de toujours
EndPoint() - avoir un point sur un POLYGON autre
que son centre en dépit de sa
StartPoint()et EndPoint() permettent facilement de convexité/concavité? - PointOnSurface()
répondre à cette question. D'où la requête suivante -
9
On pourra utiliser les fonctions respectives l'entrée la Rue Paul Valéry (table
AsText() pour avoir les points en WKT et great_roads) jusqu'à son point de
Intersects() pour les tests d'intersection rencontre (intersection) avec la Rue
Voltaire (table small_roads)? -
SELECT s.data,g.data, line_locate_point(),line_interpolate_point
AsText(Intersection(s.the_geom,g.the_geom)) () -
FROM small_roads s, great_roads g
WHERE Intersects(s.the_geom,g.the_geom) Pour répondre à cette question, il est par exemple
intéressant d'utiliser la fonction line_locate_point()
renvoyant comme résultat qui retourne pour une LINESTRING une valeur
entre 0 et 1 (relatif à un pourcentage) relative à la
data | data | astext longueur 2D de la LINESTRING en question selon
--------------+--------------------------+---------------- la position d'un point sur ou à l'extérieur de la
Rue Figaro | Rue du Général de Gaulle | LINESTRING.
POINT(60 87.5)
Rue Figaro | Rue Aristide Briand | POINT(85 Note
120)
Rue Voltaire | Rue Paul Valéry | POINT(60 Pour les besoins de cet exemple, je me sers
25) directement du résultat trouvé antérieurement à la
Rue Voltaire | Rue du Général de Gaulle | sous-section précédente, à savoir que mon point
POINT(60 87.5) d'intersection est POINT(60 25). On peut tout aussi
(4 lignes) bien prendre un autre point.
Figure 5.9. Points d'intersection entre les tables A partir de la fonction Line_locate_point(), je
small_roads et great_roads formule ma requête comme suit
SELECT
Line_Locate_Point(the_geom,GeomFromText('SRI
D=-1;POINT(60 25)')) FROM great_roads WHERE
data = 'Rue Paul Valéry';
line_locate_point
-------------------
0.716763707222655
(1 ligne)
SELECT
Line_Locate_Point(the_geom,GeomFromText('SRI
D=-1;POINT(60 25)'))*length2d(the_geom) FROM
great_roads WHERE data = 'Rue Paul Valéry';
?column?
------------------
69.1188524964988
(1 ligne
et celle-ci
La requête suivante
select
cast(area2d(intersection(r.the_geom,p.the_geom))
as decimal(15,1)) ||' m carre' as Aire
from rivers r,
parcs p
where
intersects(r.the_geom,p.the_geom);
aire
----------
123.1 m carre
(1 row)
14
1.30. Question:Quel bâtiment est contenu dans where
le parc Mangueret I? - Contains() - contains(buffer(rivers.the_geom,5),p.the_geom);
15
33. COLOR 255 0 0 nous renvoit comme réponse
34. SIZE 8
35. SYMBOL "circle" data
36. END -------------------
37. END Parc Mangueret II
END (1 ligne)
select astext(makeline(a.the_geom,b.the_geom))
from personnes a,personnes b where a.data =
'personne 5' and b.data='personne 13';
astext
-------------------------------------
LINESTRING(30.54 118.28,52.32 6.84)
(1 ligne)
17
personne 8 | POINT(115.16 34.81) | select
POINT(115.2 34.8) drop_table_if_exists('suivi_de_la_personne_7',false
personne 9 | POINT(120.89 66.23) | );
POINT(120.9 66.2)
personne 10 | POINT(137.4 62.56) | create table suivi_de_la_personne_7(
POINT(137.4 62.6) utilisateur text,
personne 11 | POINT(144.97 30.23) | POINT(145 date text,
30.2) suivi text,
personne 12 | POINT(72.04 41.23) | POINT(72 position text
41.2) );
personne 13 | POINT(52.32 6.84) | POINT(52.3 /*
6.8) Fonction appelée par le trigger
(13 lignes) */
create or replace function
1.35. Application: Utiliser les déclencheurs get_info_on_personne_7() returns trigger as $$
(triggers) en PL/PGSQL de PostgreSQL declare
pour suivre à la trace la personne 7 j record;
quand elle se déplace. Selon sa position, begin
savoir quel est le bâtiment qui lui est le if (TG_OP = 'UPDATE') then
plus proche ou le bâtiment dans lequel SELECT into j data,distance,astext(the_geom)
elle se trouve? from(
SELECT a.data,Distance
1.35.1. Fonction, table et trigger nécessaires (a.the_geom,b.the_geom),b.the_geom FROM
buildings a,personnes b
Le language PL/PGSQL sert tirer profit des WHERE b.data='personne 7'
procédures déclencheurs. Nous allons ici créer une ORDER BY distance ASC limit 1)
table suivi_de_la_personne_7 qui enregistrera à as foo;
tout moment demandé enregistrera les if j.distance=0 then
informations suivantes: insert into suivi_de_la_personne_7 values
(current_user,now(),'La personne 7 est dans
• utilisateur correspondant au nom de le batiment '''||j.data::text||'''',j.astext::text);
l'utilsateur sous de PostgreSQL qui aura fait
un update sur les données spatiales de la RAISE NOTICE 'La personne 7 est dans le
"personne 7"; batiment ''%''',j.data;
• date correspondant à l'heure à laquelle a eu else
lieu le déplacement; insert into suivi_de_la_personne_7 values
• suivi qui précisera si la personne est "dans" (current_user,now(),'La personne 7 est proche du
ou "proche" du batiment; batiment '''||j.data::text||'''',j.astext::text);
• position qui donnera la position de la
personne. RAISE NOTICE 'La personne 7 est proche du
batiment ''%''',j.data;
Nous aurons aussi besoin d'une fonction
end if;
get_info_on_personne_7() écrite en PL/PGSQL
end if;
appelé par le déclencheur qui nous renverra le
return new;
bâtiment qui contient la personne 7 et dans le cas
end;
contraire le premier bâtiment qui lui est le plus
proche.
$$ language plpgsql;
/*
/* Création du trigger
Rappel pour effacer un trigger */
drop trigger suivi_7_date on personnes; CREATE TRIGGER suivi_7_date AFTER
*/ UPDATE ON personnes
EXECUTE PROCEDURE
/* get_info_on_personne_7();
Table qui contiendra le suivi de la
personne 7 lors de ses déplacements
avec effacement éventuel avant création
*/
18
1.35.2. Modifications de la position par la postgres | 2006-01-12 12:06:05.024382+01 | La
commande UPDATE et personne 7 est proche du batiment 'Collège Arthur
GeometryFromText Rimbaud' | POINT(0 0)
postgres | 2006-01-12 12:07:31.859971+01 | La
Procédons maintenant à quelques exemples de personne 7 est proche du batiment 'E.D.F'
mise à jour des données spatiales de la personne | POINT(60 87.5)
7: (6 lignes)
madatabase=# update personnes set C'est le genre de petite application qui peut par
the_geom=geometryfromtext('POINT(100.94 exemple servir lors de suivi par une application-
105.44)',-1) where data='personne 7'; cliente (front-end) par le Web par exemple :
INFO: La personne 7 est dans le batiment interface cartographique en SVG ....
'Bibliothèque Victor Hugo'
UPDATE 1 1.35.4. Affichage avec MapServer
madatabase=# update personnes set
the_geom=geometryfromtext('POINT(100 70)',-1) Afin d'obtenir un rendu adéquate, on va
where data='personne 7'; commencer par stocker les diverses positions dans
INFO: La personne 7 est proche du batiment une petite table que nous appelerons ici
'Office du Tourisme' mouvement:
UPDATE 1
madatabase=# update personnes set create table mouvement(id serial primary key);
the_geom=geometryfromtext('POINT(120 66)',-1) select
where data='personne 7'; addgeometrycolumn('mouvement','the_geom',-
INFO: La personne 7 est dans le batiment 'Office 1,'POINT',2);
du Tourisme' insert into mouvement(the_geom)
UPDATE 1 values(geometryfromtext('POINT(100.94 105.44)',-
madatabase=# update personnes set 1));
the_geom=geometryfromtext('POINT(0 0)',-1) insert into mouvement(the_geom)
where data='personne 7'; values(geometryfromtext('POINT(100 70)',-1));
INFO: La personne 7 est proche du batiment insert into mouvement(the_geom)
'Collège Arthur Rimbaud' values(geometryfromtext('POINT(120 66)',-1));
UPDATE 1 insert into mouvement(the_geom)
madatabase=# update personnes set values(geometryfromtext('POINT(0 0)',-1));
the_geom=geometryfromtext('POINT(60 87.5)',-1) insert into mouvement(the_geom)
where data='personne 7'; values(geometryfromtext('POINT(60 87.5)',-1) );
INFO: La personne 7 est proche du batiment
'E.D.F' Afin d'afficher les divers positions successives, on
UPDATE 1 peut par exemple opter pour un layer comme suit
1.35.3. Suivi des déplacements
LAYER
CONNECTION "user=david
La simple requête suivante nous renvoit les divers dbname=madatabase host=localhost"
informations obtenues lors du déplacement de la CONNECTIONTYPE POSTGIS
personne 7 DATA "the_geom from mouvement"
LABELITEM "id"
testgis=# select * from suivi_de_la_personne_7 ; METADATA
utilisateur | date | END
suivi | position NAME "personnes"
-------------+------------------------------- SIZEUNITS PIXELS
+--------------------------------------------------------------- STATUS DEFAULT
+---------------------- TOLERANCE 0
postgres | 2006-01-12 12:05:01.989762+01 | La TOLERANCEUNITS PIXELS
personne 7 est dans le batiment 'Bibliothèque TYPE POINT
Victor Hugo' | POINT(100.94 105.44) UNITS METERS
postgres | 2006-01-12 12:05:20.824226+01 | La CLASS
personne 7 est proche du batiment 'Office du LABEL
Tourisme' | POINT(100 70) SIZE LARGE
postgres | 2006-01-12 12:05:41.106236+01 | La TYPE BITMAP
personne 7 est dans le batiment 'Office du BUFFER 0
Tourisme' | POINT(120 66)
19
COLOR 0 0 255 END
FORCE FALSE END
MINDISTANCE -1
MINFEATURESIZE -1 En ayant pris soin de définir quelque part dans la
OFFSET 0 0 mapfile, le symbole "dash" pour une ligne
PARTIALS TRUE discontinue
POSITION CC
BACKGROUNDCOLOR 255 255 255 SYMBOL
END NAME "dash"
METADATA TYPE ELLIPSE
END POINTS 1 1 END
STYLE FILLED TRUE
ANGLE 360 STYLE 10 5 5 10 END
COLOR 255 0 0 END
SIZE 2
SYMBOL "circle" L'affichage sera alors le suivant
END
END Figure 5.18. Déplacement successifs de la
END personne 7
On peut si on le souhaite joindre aussi les diverses
positions successives entre elles
LAYER
CONNECTION "user=david
dbname=madatabase host=localhost"
CONNECTIONTYPE POSTGIS
DATA "makeline from (select 1 as
id,makeline(the_geom) from mouvement) as foo
USING UNIQUE id USING SRID=-1"
METADATA
END
NAME "requete_0"
SIZEUNITS PIXELS
STATUS ON
TOLERANCE 0
TOLERANCEUNITS PIXELS
TYPE LINE
UNITS METERS
CLASS
LABEL
SIZE MEDIUM
TYPE BITMAP
BUFFER 0
COLOR 22 8 3
FORCE FALSE
MINDISTANCE -1
MINFEATURESIZE -1
OFFSET 0 0
PARTIALS TRUE
POSITION CC
END
METADATA
END
STYLE
ANGLE 360
COLOR 209 33 130
SIZE 3
SYMBOL "dash"
END
20