Vous êtes sur la page 1sur 31

support de cours

PostGIS

Cours et Support de TP

Auteur : Emmanuel Fritsch


Cration : juin 2007 3me Rvision : mars 2010

10/06/2015

Sommaire
1 Prsentation..............................................................................................................................3
1.1 Prsentation du TP............................................................................................................3
1.2 Rendu attendu...................................................................................................................3
1.3 Mthode............................................................................................................................4
1.4 Prrequis............................................................................................................................4
1.5 Matriel ............................................................................................................................4
1.6 Donnes.............................................................................................................................5
1.7 PgAdmin...........................................................................................................................5
2 Structuration de la base et insertion des donnes.....................................................................6
2.1 Dcouverte des donnes....................................................................................................6
2.2 Construction dune table...................................................................................................7
2.2.1 Modle physique des donnes................................................................................................................7
2.2.2 Construction de la table.........................................................................................................................7

2.3 Les index...........................................................................................................................8


2.4 Insertion dans la table.......................................................................................................9
2.5 le type point.....................................................................................................................10
2.6 Le type geometry.............................................................................................................11
2.6.1 Crer une colonne de type geometry....................................................................................................11
2.6.2 Remplir une colonne de type geometry................................................................................................12

2.7 Intgration dun fichier shape.........................................................................................12


3 Requtes SELECT simples....................................................................................................13
3.1 La clause WHERE..........................................................................................................13
3.2 La fonction count()..........................................................................................................13
3.3 Les Clauses ORDER BY et LIMIT.................................................................................13
4 Visualisation ..........................................................................................................................14
4.1 Visualisation sous QGIS.................................................................................................14
4.2 Visualisation en KML.....................................................................................................14
4.3 Visualisation en SVG......................................................................................................14
5 Requtes complexes...............................................................................................................14
5.1 Les vues dans PostGreSQL.............................................................................................14
5.1.1 A quoi servent les vues ? .....................................................................................................................14
5.1.2 Comment crer une vue ?.....................................................................................................................15

5.2 Sous-requtes..................................................................................................................15
6 Requtes spatiales..................................................................................................................16
6.1 Les diffrents types de gomtrie...................................................................................16
6.2 Gomtries valides et invalides.......................................................................................16
6.3 Jointures gomtriques....................................................................................................17
6.3.1 Jointures dans une requte SELECT....................................................................................................17
6.3.2 Jointures dans une requte UPDATE...................................................................................................19

6.4 Autojointure....................................................................................................................20
6.5 Autojointure et sous-requte ..........................................................................................20
7 Scripts PL/pgSQL..................................................................................................................21
8 Les index................................................................................................................................22
9 Webographie ..........................................................................................................................25
9.1 PostGreSQL....................................................................................................................25
9.2 PostGIS...........................................................................................................................25
10 A rendre................................................................................................................................26

10/06/2015

1 Prsentation
1.1 Prsentation du TP
PostGreSQL est un SGBD (Systme de Gestion de Base de Donnes) libre de trs bonne
qualit. De nombreuses applications professionnelles sont construites sur PostGreSQL.
PostGIS est une surcouche de PostGresSQL qui permet de grer la gomtrie.
Lobjectif pdagogique de ce TP est :
- de rviser les fonctions de bases des SGBD
- de vous faire dcouvrir PostGIS
- de vous amener lautonomie dans la dcouverte dun SGBD.
Les notions et techniques tudies sont :
- la connexion PostgreSQL
- le format WKT
- lintgration dans une table de fichiers shape
- les requtes smantiques et spatiales
- les jointures spatiales
- Le langage pl/pgSQL
- lutilisation des index
- laffichage des donnes en KML et en SVG
Dans le cadre de ce TP, nous allons travailler avec des donnes sismologiques dpicentre de
tremblements de terre, reprsents par des points. Nous croiserons ces donnes avec les
donnes surfaciques des surfaces terrestres du globe.

1.2 Rendu attendu


Pour vous aider maintenir votre attention tout au long du TP, et pour aider lenseignant
vous noter, certaines questions demandent de votre part que vous criviez la rponse sur
lnonc. Les questions rclamant rponses sont signales ainsi :
Question 0 Ceci est une question dont la rponse doit tre note dans le cadre n 0. Ce cadre n 0 est l
pour vous permettre de noter vos nom et prnom.

Si la rponse une question dborde de lespace qui lui est rserv, nhsitez pas continuer
au verso, en indiquant le passage au verso avec une flche lisible.
Les autres questions et les manipulations du logiciel sont indiques ainsi :
Ceci est une instruction qui ne demande pas de rendu. Mais si vous la ngligez, vous
narriverez peut-tre pas rpondre aux questions suivantes.

10/06/2015

Mme lorsque lenseignant ne demande pas que le travail lui soit rendu, il est nanmoins
conseill, pour une bonne mmorisation du cours, dcrire les rsultats lorsquils sont
demands.

1.3 Mthode
Ce TP alterne les phases o vous tes guids pas pas dans la manipulation de linterface
avec des phases qui vous mnent lautonomie. Dans cet objectif, vous devez penser aller
chercher linformation dans les documentations techniques disponibles sur internet.
Le moteur de recherche Google convient trs bien cet objectif. Si vous cherchez par
exemple de linformation sur les flageoises, une requte flageoise+tutorial vous permettra
de cibler les documents dinitiation aux flageoises, alors quune requte
flageoise+reference vous orientera efficacement vers les normes, les documentations
dtailles et les descriptions dinterface des flageoises.

1.4 Prrequis
Les prrequis de ce TP sont une connaissance pralable de PHP et dau moins un SGBD. Il
faut savoir utiliser un diteur de texte.
La connaissance de QGIS est souhaite.

1.5 Matriel
Pour mettre en uvre ce TP, il faut avoir accs un poste informatique quip :
- dun serveur postGIS avec pgAdmin,
- dun serveur web local quip de PHP, avec les extensions pgsql.
- dun navigateur, de prfrence Firefox
- dune connexion internet, pour avoir accs la documentation en ligne
- de QGIS, pour visualiser les donnes
Un bon diteur de texte, par exemple notepad++, est par ailleurs utile.
Pour vrifier la disponibilit de postGIS :
Ouvrez pgAdmin
Dans la colonne gauche de pgAdmin, vous trouvez un explorateur qui vous permet de plier et
dplier les diffrentes composantes de votre BD. Un clic droit sur un lment vous permet
daccder aux oprations autorises sur cet lment.
Dpliez la racine bases de donnes en cliquant sur la petite croix. Vrifiez que les
bases postgis et template_postgis sont prsentes. Dpliez la base postgis, dpliez
schmas , dpliez le schma public. pgAdmin vous montre alors quil y a deux
tables dans cette base.
Dpliez les tables, dpliez leurs colonnes, dpliez leurs contraintes.

10/06/2015

Ces deux tables, geometry_columns et spatial_ref_sys, sont les deux tables de gestion de
PostGIS.

1.6 Donnes
Ce TP est accompagn des donnes qui permettent de le mettre en uvre. Ces donnes sont
disponibles sur internet, ou drives de donnes disponibles sur internet :
le fichier CMT des tremblements de terre :
http://www.globalcmt.org/CMTfiles.html
le fichier des limites administratives sur ltendue du globe :
http://www.gadm.org/world
Il est recommand dutiliser les donnes telles quelles sont livres avec le TP.

1.7 PgAdmin
Dans linterface de pgAdmin, il y a trois boutons quon utilise trs souvent, et que je vous
prsente maintenant :

Le premier de ces boutons est lditeur de requte SQL. Il permet dcrire et de faire tourner
du code SQL sur une base. Le bouton nest actif que lorsquune base est slectionne.
Les deuxime et troisime boutons ne sont actifs que si une table est slectionne. Le
deuxime bouton permet dafficher toutes les donnes de la table sous la forme dun tableau.
Le troisime bouton permet de saisir un filtre sur la table pour nen afficher quun nombre
rduit de lignes (une restriction).

Lditeur de requte
Regardons plus attentivement lditeur de requte, en cliquant sur le premier des trois boutons
dcrits ci-dessus (le bouton SQL de pgAdmin). Lditeur ressemble ceci :

10/06/2015

Le cadre en haut gauche permet de taper la requte SQL. Le bouton constitu dun triangle
vert excute la requte. Le cadre en bas permet de lire la rponse la requte, et les erreurs
ventuelles.
Tapez le code SQL suivant : SELECT 2+2, puis cliquez sur le triangle vert.
Tapez le code SQL suivant : SELECT * FROM geometry_columns, et vrifiez que
cette table est vide.
Tapez le code SQL suivant : SELECT * FROM spatial_ref_sys, vrifiez que cette
table est peuple.
Tapez le code SQL suivant : SELECT * FROM spatial_ref_sys WHERE srid=4326.
On trouve la rfrence la projection plate carre que nous utiliserons dans le cours de
ce TP.
Tapez le code SQL suivant :
SELECT * FROM spatial_ref_sys WHERE srtext LIKE '%Douala%'.
Cette requte permet de trouver toutes les projections dont la description contient le
mot Douala . La projection actuellement utilise sur le Cameroun y est-elle
rfrence ?

2 Structuration de la base et insertion des donnes


2.1 Dcouverte des donnes
ouvrez le fichier CMT au format .ndk pour la priode 1976-2005

10/06/2015

Regardez rapidement les donnes (la premire ligne), et la description du format .ndk.

2.2 Construction dune table


Le fichier lectureFichierCMT.php permet de faire une insertion dans mySQL. Le problme
de mySQL, est que sa cartouche spatiale est moins performante que celle de PostGIS. Nous
allons donc modifier ce script lectureFichierCMT.php pour que linsertion se fasse dans
PostGreSQL plutt que dans mySQL.
Avant de faire les insertions dans une table des tremblements de terre, nous devons crer cette
table. Et avant de crer la table, nous devons construire le modle physique des donnes.
Donc : dans un premier temps on analyse lectureFichierCMT.php pour lister les colonnes
que nous allons mettre dans notre table. Ensuite, nous allons utiliser pgAdmin pour construire
la table des tremblements de terre. Pour finir, le script lectureFichierCMT.php sera modifi,
pour faire linsertion SQL.

2.2.1 Modle physique des donnes


Pour dfinir le format de la table dans laquelle seront rangs les tremblements de terre,
analysez l'instruction SQL "INSERT" qui se trouve dans lectureFichierCMT.php :
elle vous permet de faire la liste des colonnes que nous devons prvoir pour notre table
PostGIS.
Truc et Astuce : parmi les petits dtails que vous ne pouvez pas deviner tout seul, apprenez
que pour la colonne dateheure, nous allons utiliser un type SQL qui sappelle timestamp
without time zone.
Notez au passage que PostgreSQL ne fait pas dans la concision. SQL en gnral prfre des noms rallonge
mais faciles comprendre, plutt que courts mais sotriques.
Question 1- Ecrivez la liste des colonnes avec leur type.

2.2.2 Construction de la table


Pour construire rapidement la base en apprenant vous servir de pgAdmin, je vous conseille
de suivre pas pas les instructions qui suivent :
clic droit sur "base de donnes", "ajouter une BD".
Saisissez le nom de la base (tremblement_de_terre) et son modle
(template_postgis)
Avec OK, la BD est cre.
Dpliez tremblement_de_terre, dpliez Schmas , dpliez le schma public,
dpliez Tables .
Vrifiez que les 2 tables de postGIS sont prsentes ( geometry_columns et
spatial_ref_sys). Si elles ne sont pas prsentes, cela signifie que vous avez oubli
de mettre template_postgis en modle de votre BD.
Au passage, vrifiez quil y a aussi quelques centaines de fonctions. Le nombre exact
varie selon la version de PostGIS.

10/06/2015

clic droit sur public


Ouvrez "ajouter un objet" / "ajouter une table".
Premier onglet : Saisissez le nom de la table : tdt
Second onglet : Saisissez les noms de colonnes (avec leur type) :
o id (de type SERIAL),
o dateHeure (de type timestamp without time zone),
o latitude, longitude et les autres (de type real).
Troisime onglet : ajoutez une clef primaire, portant sur la colonne id.
Cliquez sur OK : la table est cre.

Si vous ne saisissez pas de clef primaire, un message vous avertit que vous navez pas de clef
primaire sur votre table, ce qui limitera les oprations que vous pouvez faire avec. En
particulier avec pgAdmin, vous ne pourrez pas modifier les donnes en table. Cest pour cette
raison que nous avons cr une colonne didentifiant.
Dans une base avec plusieurs tables et des liens explicites entre tables, lidentifiant sert de
support aux liens entre tables, et garantit lintgrit de linformation porte par le lien.
Plus prcisment, si la colonne enseignant de la table cours contient Emmanuel Fritsch et quil y a plusieurs
Emmanuel Fritsch dans la table enseignant, on introduit une ambigut dans la base. En revanche, si la colonne
enseignant de la table des cours contient lidentifiant de lenseignant, cette colonne pointe vers lenseignant de
manire fiable et sans ambigut.

Le type SERIAL
Quel est donc ce type SERIAL que nous avons affect la colonne id ?
Le type SERIAL est un raccourci qui permet en une seule dclaration :
- de crer une colonne de type integer
- de lui ajouter, en valeur par dfaut, une valeur incrmentale
- de crer le compteur spcifique qui va grer cet incrment. Ce compteur sappelle une
squence (du latin sequor, suivre).
Vrifiez que la squence a t cre.
Vrifiez que la valeur par dfaut de la colonne id est la valeur du compteur
incrmente.
Question 2 Trouvez dans pgAdmin linstruction SQL qui dit que la valeur par dfaut de la colonne id
est la valeur du compteur incrmente. Recopiez-la.

2.3 Les index


Pour manipuler plus facilement les objets, on utilise des index. Un index est un mcanisme
qui acclre la manipulation des objets partir de leurs attributs. Une bonne gestion des index
est ncessaire pour donner votre base de donnes une efficacit optimale. A contrario, si
vous ne dfinissez pas dindex, ou bien si vous les dfinissez mal, votre base de donnes
tournera de manire trs trs ralentie.
10/06/2015

Pour mettre un index sur la colonne magnitude :


- on dplie la table tdt, on dplie index .
- clic droit sur index , ajouter un index
- onglet proprit : on donne un nom cet index (par exemple k_magnitude) et on
choisit la mthode daccs btree
- onglet colonnes : on slectionne magnitude, et on clique sur ajoute .
- on valide avec OK
Dans notre base, nous allons pour le moment mettre des index sur les colonnes magnitude et
profondeur.
En suivant les instructions ci-dessus, mettez un index sur les colonnes magnitude et
profondeur.

2.4 Insertion dans la table


Nous allons maintenant adapter le fichier lectureFichierCMT.php pour quil fasse
linsertion dans la table tdt. Les fonctions PHP pour manipuler PostGreSQL et mySQL sont
trs proches. Gnralement, une fonction pour mySQL, reconnaissable son prfixe mysql_,
est lexacte parallle dune fonction pg_, mais de petites diffrences se glissent parfois dans le
dcor. Ainsi, pour se connecter une base, on utilise pg_connect pour PostGreSQL et
mysql_connect pour mySQL, mais les paramtres de ces deux fonctions ne sont pas les
mmes.
Dans tous les cas, il vaut mieux se rfrer la documentation en ligne (par exemple :
http://fr.php.net/pgsql)
Modifiez et compltez le fichier lectureFichierCMT.php pour quil fasse linsertion
dans la table tdt.
Il faut penser remplacer tous les prfixes mysql_ par les prfixes pg_. Dans le code,
vous devez remplacer les XXX par les instructions correctes.
crez le fichier connexion.inc.php
Vous irez chercher dans la documentation de postGreSQL la syntaxe de la fonction
pg_connect().
Dbuguez le code jusqu ce quil fonctionne.
On vrifie que le code fonctionne en affichant le contenu de la table dans pgAdmin.
Lorsque le code fonctionne :
- supprimez la dernire ligne ($clef>100),
- avec pgAdmin, videz la base des donnes que vous avez dj inscrites (cherchez la
syntaxe de la fonction DELETE dans la documentation PostGreSQL)
- relancez lintgration des donnes dans la base

Elapsed Time

10/06/2015

Attention, il arrive que le programme sarrte avant davoir lu toutes les donnes. En effet,
pour des raisons de scurit, le serveur arrte les scripts qui durent trop longtemps. Par dfaut,
la dure maximale dun script est de 30 secondes.
Le serveur affiche alors une erreur elapsed time , ou un message quivalent. Pour rsoudre
ce problme ventuel, vous devez allonger la dure maximale accorde chaque script.
Mme si votre script a tourn en moins de 30 secondes, je vous demande de faire lexercice
qui consiste trouver comment rgler ce problme.
trouvez comment allonger la dure maximale du script PHP sur votre serveur local (la
solution est srement sur internet).
Question 3 Dcrivez comment vous allongez la dure maximale du script PHP sur votre serveur local.
Donnez la requte google (ou autre) qui vous a conduit au rsultat.

2.5 le type point


La connaissance de la latitude et la longitude permet de positionner un tremblement de terre,
mais dun point de vue conceptuel, ces deux valeurs sont en fait les deux composantes dune
ralit gomtrique : le point. Dans PostGreSQL, il existe un type point qui permet de stocker
sur une seule colonne les deux valeurs de latitude et longitude.
Avec pgAdmin, ajoutez la table tdt une colonne pt de type point (clic droit sur tdt,
ajouter un objet , puis ajouter une colonne ).
Vrifiez dans pgAdmin que la colonne a t cre et quelle est vide.
On pourrait modifier de nouveau le fichier lectureFichierCMT.php pour lui faire ajouter
linsertion dun point. Si on utilisait cette mthode, il faudrait vider la base pour la remplir de
nouveau.
De manire plus simple, nous allons utiliser, sur pgAdmin, une requte UPDATE qui partir de
la base prcdente va remplir la colonne pt.
Cherchez dans la documentation de PostGres le format dentre dun point.
Testez-le dans une case de la colonne pt, dans la table tdt.
Tapez la requte UPDATE qui remplit la colonne pt avec les informations des colonnes
latitude et longitude.
Faites tourner cette requte pour remplir correctement la colonne pt.
Question 4 Recopiez votre requte UPDATE de la colonne pt.

Malheureusement, le type point de PostgreSQL, introduit pour manipuler des gomtries, na


pas reu les fonctions qui permettent cette manipulation. Par ailleurs, le type point ne permet
pas de coder simplement des objets lignes et surfaces.

Le type point nest pas utilisable pour une application manipulant


massivement des gomtries dobjet.
10/06/2015

10

Dans la suite du TP, nous travaillerons principalement avec le type geometry. Nous
reviendrons sur le type point la fin du TP, pour montrer que le type geometry lui est
largement suprieur.

2.6 Le type geometry


2.6.1 Crer une colonne de type geometry
Le type point nest pas un type de PostGIS : il appartient PostGreSQL. Comme PostGIS est
la vraie composante spatiale de PostGreSQL, le type point na pas subi les dveloppements
et les optimisations que nous allons trouver dans PostGIS.
Pour profiter de la puissance de PostGIS, nous allons maintenant rajouter une colonne de type
geometry dans notre table tdt.
Attention : la structuration de notre BD nest pas optimale. Dans une vraie BD, nous viterons
de dupliquer linformation gomtrie sous la forme 1- latitude/longitude, 2- type point de
PostGreSQL, 3- type geometry de PostGIS.
La double redondance de nos gomtries est ici purement pdagogique : elle va nous
permettre de faire des comparaisons entre les diffrents formats de nos colonnes.
Pour crer une colonne de type geometry, on utilise la commande SQL suivante :
SELECT AddGeometryColumn( 'nom_de_la_table',
'nom_de_la_colonne',
srid,
'type_de_gomtrie',
dimension );

avec :
- Le SRID est un identifiant de la projection utilise. Sauf prcision contraire, nous
nutiliserons dans ce TP que la projection plate carre, dont lidentifiant est 4326.
- La dimension est 2 ou 3, selon que les donnes sont en 2D ou en 3D. Ici, la dimension
sera toujours 2.
Il est possible de crer une colonne de type geometry directement, comme on a cr la
colonne de type point. Lintrt de passer par la fonction AddGeometryColumn est de mettre
jour la table geometry_columns. Cette dernire est utilise par certaines applications qui
suivent les recommandations de lOpen GIS Consortium (OGC).
La table geometry_columns stocke les mta-donnes sur les colonnes de type geometry. Ces
mta-donnes sont requises par certaines applications qui suivent les recommandations de
lOpenGIS.
Dans lditeur SQL de PgAdmin, crivez la commande SQL en utilisant la fonction
AddGeometryColumn pour crer geom, une colonne de type geometry sur la table tdt.
Avec pgAdmin, crez une colonne geom2 de type geometry.
Lisez le contenu de la table geometry_columns. Vrifiez que geom est rfrence, et
que geom2 est absente.
Supprimez la colonne geom2.

10/06/2015

11

Pour crer une colonne de type geometry, il est recommand dutiliser la


fonction AddGeometryColumn. Pour la dtruire, on utilisera la fonction
DropGeometryColumn.
Question 5 Recopiez linstruction qui vous a permis de crer la colonne geom.

2.6.2 Remplir une colonne de type geometry


Cherchez dans la documentation de PostGIS le format dentre dun point dans une
colonne de type geometry (indice : WKT, geomFromText)
Attention, cette fois-ci, vous ne pouvez pas tester ce format dans une case du tableau de
donnes, car cest une fonction. Vous allez directement crire la requte SQL UPDATE dans
lditeur de requte.
Ecrivez la requte UPDATE, et faites-la tourner pour remplir la colonne geom.
Question 6 Recopiez la requte UPDATE de la colonne geom.

2.7 Intgration dun fichier shape


Nous allons maintenant ajouter notre base un fond de plan qui permettra de replacer les
tremblements de terre par rapport aux continents.
Si nous affichions nos donnes maintenant, elles seraient trs peu lisibles : une collection de
points dont la signification et la position terrestre seraient trs difficiles analyser. Pour
donner du sens nos donnes, nous allons les placer sur un fond de plan. Ce fond de plan est
un produit driv par simplification du fichier gadm.shape de luniversit de Berkeley.
Dans linvite de commande (accessible par le menu PostGreSQL), nous allons lancer le
programme shp2pgsql. La syntaxe de linstruction shp2pgsql est la suivante :
shp2pgsql -s 4326 -c -D -i -I D:\partage\gadm\MondeGadm.shp monde >
monde.sql

Cette instruction ( taper sur une seule ligne) prend en entre le fichier MondeGadm.shp et
crit les instructions qui vont permettre de construire la table monde. Ces instructions sont
enregistres dans le fichier monde.sql.
Il faut ensuite intgrer ce fichier monde.sql dans la base tremblement_de_terre :
psql -d tremblement_de_terre -h localhost -U postgres -f monde.sql

Dans linvite de commande de PostGresSQL, faites tourner les deux instructions


prcdentes.

10/06/2015

12

En vous aidant de sa commande daide (shp2pgsql ?), dterminez la signification de


loption I de shp2pgsql.
Question 7 Cherchez dans pgAdmin le nom de lobjet cr par loption -I.

3 Requtes SELECT simples


3.1 La clause WHERE
La requte SELECT permet dextraire des informations dune table.
1- On na pas besoin dextraire toutes les colonnes. On indique les noms des colonnes
extraire :
SELECT id, magnitude, geom FROM table

2- Et surtout, on na pas besoin dextraire toutes les lignes (tous les objets stocks dans la
table). On donne les conditions que doivent remplir les objets extraire :
SELECT id, magnitude, geom FROM table WHERE magnitude>5.5

Ici, seuls les objets de magnitude suprieure 5.5 sont retenus.


Les conditions que doivent respecter les objets extraire sont spcifies au moyen de la
clause WHERE. Il est possible de combiner plusieurs conditions avec les oprateurs boolens
AND et OR. Par exemple :
SELECT id, magnitude, geom
FROM table
WHERE magnitude>5.5 AND profondeur>500

Adaptez la requte prcdente et faites-la tourner sur la base.

3.2 La fonction count()


Dans la documentation de PostGreSQL, trouvez la signification de la fonction
count() ; utilisez-la pour dterminer le nombre dobjets dans la table monde. Vrifiez
que le nombre trouv correspond celui donn par pgAdmin (cadre en haut droite).
Ecrivez la requte qui dtermine le nombre de tremblements de terre qui rpondent
la condition magnitude>5.5 AND profondeur>500.
Question 8 - Recopiez cette requte et son rsultat

3.3 Les Clauses ORDER BY et LIMIT


Dans la documentation de PostGreSQL, trouvez la signification de la clause ORDER BY
et de la clause LIMIT.
Ecrivez la requte qui trouve la magnitude du tremblement de terre le plus profond.
Ecrivez la requte qui trouve la magnitude du tremblement de terre de plus forte
magnitude.

10/06/2015

13

Question 9 Recopiez les deux requtes, et leur rsultat.

4 Visualisation
4.1 Visualisation sous QGIS
Ouvrez QGIS.
Dans QGIS, ouvrez une connexion avec la base de donnes (ajouter une couche /
couche PostGIS).
Choisissez les tables et les colonnes que vous voulez afficher.
Contrlez que les donnes sont cohrentes (accumulation des tremblements de terre
sur les limites de faille, par exemple sur lIndonsie et la Cordillre des Andes).
Si les donnes ne sont pas cohrentes, cherchez la source du problme.
Limitez laffichage des donnes aux seuls tremblements de terre de magnitude
suprieure 5.5.

4.2 Visualisation en KML


KML est le format standard de Google Earth.
Trouvez sur internet la mthode pour faire un export de PostGIS au format KML.
Affichez dans Google Earth les 100 tremblements de terre de plus grande magnitude

4.3 Visualisation en SVG


SVG est un format vecteur que vous pourrez visualiser par exemple avec FireFox (format
natif depuis la version 1.1).
Mmes questions que pour KML.

5 Requtes complexes
5.1 Les vues dans PostGreSQL
Attention, attention : une vue SQL est un concept purement SGBD, qui na rien voir avec la
visualisation des donnes.

5.1.1 A quoi servent les vues ?


Dans PostGreSQL, il est possible dcrire des requtes qui slectionnent les 200 tremblements
de terre de plus forte magnitude. Pour cela, on utilise les clauses ORDER BY LIMIT .

10/06/2015

14

Dans QGIS, il nest pas possible de limiter laffichage des donnes aux 200 tremblements de
terre de plus forte magnitude, en utilisant ces clauses ORDER BY LIMIT . Pour faire cette
opration, il faut dfinir une vue dans PostGIS, et appeler cette vue dans QGIS.

Une vue, en SQL, est une table virtuelle on peut faire sur cette table des
requtes SELECT, mais pas dinsertion ni de mise jour (requtes INSERT et
UPDATE).
Derrire cette table virtuelle se cache une requte qui permet daccder aux
donnes qui se trouvent dans les vraies tables de la base.
5.1.2 Comment crer une vue ?
Pour crer une vue :
- dpliez le schma public de votre BD,
- clic droit sur vue , puis ajouter une vue ,
- dans longlet proprit , donnez-lui un nom (comme un nom de table),
- dans longlet dfinition , entrez la requte SQL qui correspond cette vue (requte
que vous aurez teste au pralable),
- cliquez sur OK.
La vue est cre. Vous pouvez la tester.
Crez la vue qui correspond aux seuls tremblements de terre de magnitude suprieure
5.5.
Crez la vue tdt_magni_sup qui correspond aux 200 tremblements de terre de plus
forte magnitude.
Avec la fonction count(), vrifiez quil y a bien 200 tremblements de terre dans cette
vue.
Ecrivez la requte SELECT qui dtermine la magnitude du plus faible tremblement de
terre de la vue.
Question 10 Recopiez la requte qui cre la vue correspondant aux 200 tremblements de terre de plus
forte magnitude.

Question 11 Recopiez la requte qui dtermine la magnitude du plus faible tremblement de terre de cette
vue.

5.2 Sous-requtes
Dans cette partie, nous allons essayer de trouver la requte qui rpond la questions suivante :
quelle est le minimum, le maximum et la moyenne des magnitudes pour les 8000
tremblements de terre les plus profonds.
Pour cela, nous utiliserons les sous-requtes.

Une sous-requte est une requte dont le rsultat est utilis dans une autre
requte (la requte principale). Le rsultat de la sous-requte est considr
comme une table.

10/06/2015

15

crivez la requte qui calcule la moyenne, le minimum et le maximum de toutes les


magnitudes (R1)
En vous aidant de la documentation, utilisez la clause OFFSET pour trouver la
profondeur du 8000e tremblement de terre le plus profond. (R2)
Ecrivez la requte qui renvoie les 8000 tremblements de terre les plus profonds (R3)
Utilisant cette requte R3 comme sous-requte, calculez la moyenne, le minimum et le
maximum de la magnitude. (R4)
La requte R3 utilise dans R4 est une table temporaire. Lutilisation dune vue donnerait le
mme rsultat. Si pour des raisons despace mmoire on souhaite ne pas utiliser des sousrequtes renvoyant des tables, on peut utiliser des sous-requtes renvoyant des valeurs isoles.
Utilisez R2 pour crer une requte qui renverra le minimum et le maximum de la
magnitude sur les 8000 tremblements de terre les plus profonds.

6 Requtes spatiales

6.1 Les diffrents types de gomtrie


Cherchez dans la documentation de PostGIS les diffrents types de gomtrie que
manipule PostGIS

6.2 Gomtries valides et invalides


Quest-ce quune gomtrie valide ? Comment teste-t-on quune gomtrie est valide ?
Ecrivez et testez la requte qui compte le nombre de gomtries invalides dans les
tables tdt et monde.
Quelle est laire maximale parmi les gomtries invalides dans la table monde ?
Affichez dans QGIS toutes les surfaces non valides.
Est-il raisonnable de supprimer de la table monde les objets dont les surfaces ne sont
pas valides ?
Et si on utilisait la fonction buffer() pour rendre les gomtries valides ?

10/06/2015

16

lire la dfinition de cette fonction


On y va prudemment !
o Crez la colonne geom2 dans monde.
o Faites une requtes de dbugage : UPDATE SET geom2= WHERE gid<10.
o Lorsque la requte fonctionne, appliquez-l toutes les gomtries nonvalides.
o Comptez le nombre de gomtries invalides dans geom2.
o Affichez geom2 dans QGIS. Contrlez visuellement le rsultat.
o Cherchez le maximum de la diffrence des aires entre geom2 et the_geom.
o En quelle unit est exprime cette diffrence de surface ? Donnez un majorant
de cette diffrence, dans une unit pertinente du systme mtrique.
o Injectez geom2 dans the_geom et supprimez geom2.

6.3 Jointures gomtriques


Nous allons parler dans cette partie des jointures gomtriques, qui constituent une classe
particulire de jointures.

Une jointure est un mcanisme permettant dextraire de linformation qui se


trouve rpartie dans deux tables diffrentes.
Plus exactement, la jointure est le mcanisme qui consiste apparier les
objets dune table avec les objets dune autre table.
Le concept de jointure, trs important en SQL et plus largement en base de
donnes relationnelle, nest pas abord ici. Ce concept ne constitue pas un
prrequis de ce cours, mais je vous encourage vivement lacqurir si vous
ne le matrisez pas encore.

6.3.1 Jointures dans une requte SELECT


Nous allons appliquer le concept sur un exemple simple : je cherche faire la diffrence entre
les tremblements de terre terrestres et les tremblements de terre sous-marins. Linformation
sur les tremblements de terre se trouve dans la table tdt (ou dans la vue tdt_magni_sup, car
nous allons nous restreindre aux tremblements de terre les plus puissants).
Mais pour connatre la nature terrestre ou sous-marine du tremblement de terre, nous devons
aller chercher linformation dans la table monde.
Le mcanisme qui permet dinterroger les deux tables en mme temps sappelle la jointure. Si
je cherche la liste des tremblements de terre terrestre, ma requte de jointure va scrire :
SELECT t.id, t.geom, t.magnitude
FROM tdt_magni_sup AS t, monde AS m
WHERE within( t.geom, m.the_geom )

Analysons les diffrentes clauses de cette requte, en commenant par le FROM :


10/06/2015

17

FROM tdt_magni_sup AS t, monde AS m :


tdt_magni_sup et monde. La clause AS sert

la clause FROM comporte ici deux tables,


dfinir, pour chaque table, un alias. Ceci
nous permet dutiliser dans la requte un nom plus court, pour que la requte soit plus
lisible.
SELECT t.id, t.geom, t.magnitude : la liste des colonnes que nous allons garder.
Pour indiquer au SGBD dans quelle table se trouve chacune des colonnes recherches,
nous prfixons le nom de la colonne avec lalias de la table.
WHERE within( t.geom, m.the_geom ) : ceci est la condition de jointure. La
fonction whithin(), offerte par PostGIS, permet de dterminer si une gomtrie (le
premier paramtre de la fonction) est incluse dans une seconde gomtrie (le second
paramtre). Notez quici aussi les noms de colonne sont prfixs par les noms de table.

Attention :
- tdt_magni_sup nest pas une table, cest une vue, mais tant quon reste dans une
requte SELECT, les vues sont utilises comme des tables.
- En gnral, on nest pas oblig de prfixer les noms de colonnes avec les noms de leur
table, mais cela facilite la lisibilit du code. Il est donc recommand de le faire.
- Il y a un cas o on est oblig de prfixer les noms de colonnes, cest lorsque le nom de
colonne apparat dans les deux tables. Cest courant avec les colonnes nom, id, et gid,
mais aussi proprietaire, date, etc.
- Dans le cas gnral, on nest pas oblig de mettre un alias sur les tables.
- Il y a un cas o on est oblig de mettre un alias, cest le cas de lauto-jointure, c'est-dire lorsque la table figure deux fois dans la jointure. Nous verrons ce cas un peu plus
loin.
- Lorsquon met un alias sur une table, on na plus le droit dutiliser le nom de la table :
dans toute la requte, lalias doit remplacer le nom de la table.
Revenons notre requte :
SELECT t.id, t.geom, t.magnitude
FROM tdt_magni_sup AS t, monde AS m
WHERE within( t.geom, m.the_geom )

Testez cette jointure dans pgAdmin.


Transformez cette jointure pour quelle renvoie, outre les colonnes dj spcifies, le
nom du pays dans lequel a eu lieu le tremblement de terre.
Question 12 Recopiez la requte modifie

Transformez cette jointure pour quelle renvoie le nombre de tremblements de terre,


parmi les 200 plus forts, qui sont terrestres.
Le contraire de within() est NOT within(). Transformez la requte pour compter les
tremblements de terre, parmi les 200 plus forts, qui sont sous-marins.
Vrifiez le rsultat : la somme des deux fait-elle 200 ?
Question 13 Ecrivez le nombre de tremblements de terre, parmi les 200 plus forts, qui sont terrestres.
Ecrivez le nombre de tremblements de terre que lon trouve si lon transforme within() en NOT
within().

La plupart des tudiants qui ne savent pas ce quest une jointure trouvent ici un rsultat
aberrant, et sen tonnent. Comment est calcule la jointure ?

10/06/2015

18

Pour la premire requte, le SGBD considre tous les couples (tremblement de terre ;
contour de pays) et il ne garde que ceux pour lequel le tremblement de terre est
lintrieur du pays. le SGBD ne retient que les tremblements de terre associs un
contour, et comme les contours de pays sont disjoints, chaque tremblement de terre
nest retenu quune seule fois.
Pour la deuxime requte, si vous remplacez la condition within() par une condition
NOT within, le SGBD va considrer tous les couples. Or, pour chaque tremblement de
terre, on va trouver un grand nombre de pays dans lequel ce tremblement de terre ne se
trouve pas : chaque fois, le couple (tremblement de terre ; contour de pays) qui
correspond ce critre sera retenu.

Vous devez rflchir votre condition de jointure en gardant en mmoire le mcanisme de


jointure dcrit ici : le SGBD prend en compte toutes les paires que lon peut construire avec
les lments des deux tables, et limine les paires qui ne respectent pas la condition de
jointure.

6.3.2 Jointures dans une requte UPDATE


Il est possible de faire des jointures dans une requte UPDATE, avec les limitations naturelles
suivantes :
- La mise jour ne pourra concerner quune seule table.
- Cette table doit tre une vraie table. Pas de mise jour sur une vue !
Nous allons voir cela tout de suite sur un exemple : pour pouvoir slectionner les
tremblements de terre sous-marins, nous allons ajouter dans la table tdt une colonne qui
portera linformation terrestre/sous-marin. Cette colonne sera nomme terrestre, et sera de
type boolen. Puis nous remplirons cette colonne au moyen dune requte de mise jour, qui
utilisera une jointure sur la table monde :
UPDATE tdt
SET terrestre=true
FROM monde
WHERE st_within(tdt.geom, monde.the_geom)

Dans la table tdt, ajoutez une colonne terrestre, de type boolen (boolean).
Faites tourner la requte UPDATE ci-dessus.
Ecrivez et faites tourner la requte UPDATE qui va mettre false les valeurs qui ne
sont pas dj true.
Nous allons nous intresser maintenant aux tremblements de terre qui se trouvent en mer,
mais une distance rduite du rivage, par exemple moins de 10 km. Nous disposons de deux
mthodes pour cela :
- soit nous appliquons un buffer de 0.1 (environ 10 kilomtres) sur les terres merges,
puis nous slectionnons les tremblements de terre qui appartiennent ce buffer. Pour
appliquer le buffer, il faut au pralable avoir regroup toutes les terres merges en
une seule gomtrie.
- soit nous utilisons la fonction dwithin() qui correspond exactement notre demande.
cherchez la documentation de dwithin(), crivez la requte SELECT, puis testez l.
XXX la documentation est ambigu quant lunit utilise dans le calcul. Inventez une
manipulation qui fixe cette ambigut.

10/06/2015

19

6.4 Autojointure
Notre objectif dans cette partie est de construire le contour des zones de forte sismicit. Une
zone sismique est une zone o il y a beaucoup de tremblement de terre. Nous allons la
calculer de la manire suivante :
- Nous allons isoler les tremblements de terre qui ont plus de N tremblements de terre
autour deux, dans un rayons de R kilomtres.
- Autour de ces tremblements de terre, nous allons tracer la zone des points qui sont
moins de R2 kilomtres.
Lune des difficults, que nous nallons pas traiter ici, tient la projection que nous utilisons :
le calcul de la distance sur la sphre ne passe pas par la simple somme des carrs des
coordonnes angulaires. Les distances que nous allons utiliser sont donc fausses, et ce
dautant plus quon slve en latitude.
Pour dtecter les tremblements de terre qui sont proches dautres tremblements de terre, nous
devons croiser la table tdt avec elle-mme. La syntaxe ressemble ceci :
SELECT t1.id, t1.geom, t1.magnitude
FROM tdt AS t1, tdt AS t2
WHERE st_distance(t1.geom, t2.geom)<0.8

Cette requte est une auto-jointure. Ici, lalias de table est obligatoire.
Ne testez pas cette requte : elle est vraiment trs coteuse en temps.
Pourquoi est-elle coteuse en temps ?
Pour ne pas avoir recalculer sans cesse cette requte, nous allons stocker son rsultat dans
une colonne possede_voisin, qui indiquera si le tremblement de terre est isol ou pas.
Crez la colonne possede_voisin, de type boolen.
Rcrivez la requte ci-dessus pour en faire une requte de mise jour de la colonne
possede_voisin.
Question 14 Recopiez cette requte de mise jour.

Si vous voulez tester le temps dexcution de cette requte, prvoyez une pause djeuner,
voire une petite sieste.

6.5 Autojointure et sous-requte


Pour savoir si un tremblement de terre est vraiment isol, ce nest pas la prsence dun voisin
qui compte, mais de plusieurs voisins : nous allons caractriser une zone sismique par la
prsence dau moins 3 voisins dans un rayon de 1.2 degrs.

10/06/2015

20

Pour compter le nombre de voisins, nous allons maintenant utiliser la technique des sousrequtes :
UPDATE tremblementdeterre AS t3
SET nbre_voisins=nbre
FROM (
SELECT t1.id, count(*) AS nbre
FROM tremblementdeterre AS t1, tremblementdeterre AS t2
WHERE ST_DWithin(t1.geom, t2.geom, 2)
GROUP BY t1.id
) AS t4
WHERE t3.id=t4.id

Crez dans la table tdt la colonne qui permet de stocker le nombre de voisins de
chaque tremblement de terre
Question 15 En vous aidant de la documentation, analysez les diffrents termes de la requte prcdente
pour en donner la signification. Que reprsente t4 ?

Faites tourner la requte. Visualisez son rsultat sous QGIS.


En vous aidant de la documentation, crivez la requte qui construit la zone sismique
sous la forme dun tampon autour des tremblements de terre possdant au moins 3
voisins.
Visualisez la zone sismique sous QGIS.
construisez autour des terres merges un tampon dun demi degr.

7 Scripts PL/pgSQL
Dans la premire partie de ce TP, nous avons utilis un script PHP pour mettre en forme des
donnes dans la base. Cette mthode, parce quelle implique un change systmatique des
donnes entre le script et le SGBD, est coteuse en temps. Il est plus intressant de faire
tourner un script directement dans le SGBD.

PostGreSQL possde un langage de script : PL/pgSQl.


Ce langage permet de dfinir des fonctions, que lon peut appeler ensuite dans nimporte
quelle expression, par exemple avec une requte SELECT.
Pour faire des tests de charge de PostGIS, nous allons peupler la base avec des
enregistrements fictifs, pour lui faire contenir environ un million dobjets.
Adaptez le code suivant la table des tremblements de terre :

10/06/2015

21

CREATE OR REPLACE FUNCTION ajoute_valeurs_aleatoires(nbre integer)


RETURNS void AS $$
DECLARE
-- declarations
BEGIN
FOR i IN -179 .. 179 LOOP
FOR j IN -89 .. 89 LOOP
FOR k IN 1 .. nbre LOOP
INSERT INTO table(x,y) VALUES ( i+random() , j+random() ) ;
END LOOP ;
END LOOP ;
END LOOP ;
END;
$$ LANGUAGE plpgsql;

Ajoutez la fin du code les instructions qui permettent de remplir les colonnes pt et
geom avec les valeurs qui se trouvent dans les colonnes latitude et longitude.
Pour appeler cette fonction qui ne renvoie pas de rsultat, on utilise la syntaxe suivante :
SELECT ajoute_valeurs_aleatoires(3) ;

Faites tourner cette fonction pour obtenir entre un demi-million et un million


denregistrements.
Combien avez-vous maintenant dobjets dans la table des tremblements de terre ?
Question 16 - Ecrivez le nombre dobjets qui sont maintenant dans la table des tremblements de terre.

8 Les index
Nous commenons par deux mises en garde :

Attention : les manipulations demandes dans cette partie sont un peu


rptitives, et demandent de votre part de travailler avec soin.
et :

Lorsque le TP vous demande de noter un temps dexcution, vous ne devez


avoir aucun autre programme qui tourne sur votre machine. En particulier
les programmes de messageries, et tout autre programme faisant des accs
rseaux inopins doivent tre teints. De mme, efforcez-vous de maintenir
ltat de votre machine constant durant toute la dure de cette partie, pour
que les valeurs numriques observes aient la plus grande signification
possible.
Dans cette partie, nous allons utiliser le gestionnaire de requte SQL, que lon ouvre avec le
bouton SQL de pgAdmin :

10/06/2015

22

crivez une requte qui permette de slectionner les tremblements de terre qui ont eu
lieu entre 10 et 11 degrs de latitude et entre 10 et 11 degrs de longitude.
Ouvrez une nouvelle fentre de requte SQL. A laide de la documentation de
postGreSQL, crivez la mme requte, mais en faisant porter la slection sur la
colonne pt de type point.
Ouvrez une troisime fentre de requte SQL. A laide de la documentation de
postGIS, crivez la mme requte, mais en faisant porter la slection sur la colonne
geom de type geometry. Vous DEVEZ utiliser la fonction geomFromText.
Note pour le prof : la syntaxe WHERE geom && 'WKT' semble valide, mais plante lorsquon
modifie les index. A claircir.
Question 17 - Lorsque les trois requtes fonctionnent correctement, notez les conservez aussi les trois
fentres avec les trois requtes (elles vont servir tout de suite).

Ecrivez EXPLAIN au dbut dune des trois requtes. Relancez. Regardez le rsultat.
Enlevez EXPLAIN . Vrifiez le rsultat.

Question 18 - En vous aidant de la documentation, expliquez prcisment quoi sert linstruction


EXPLAIN.

Question 19 Excutez les instructions suivantes et notez soigneusement les rsultats qui apparaissent
lcran.

Reprenez la requte sur les latitudes et les longitudes.


Changez les valeurs, pour chercher les vnements entre 20 et 21 degrs, tant en
latitude quen longitude.
Lancez cinq fois cette requte, en notant les temps raliss chaque fois.
Ecrivez EXPLAIN en dbut de requte. Lancez la requte. Notez le rsultat.
Sur les colonnes latitude et longitude, mettez un index btree. Relancez cinq fois
la requte (sans EXPLAIN) puis une fois avec EXPLAIN. Notez les rsultats.
Sur les mmes colonnes latitude et longitude, ajoutez un index gist (en laissant
lindex btree). Relancez cinq fois la requte (sans EXPLAIN) puis une fois avec
EXPLAIN. Notez les rsultats.
Enlevez lindex btree (en laissant lindex gist). Relancez cinq fois la requte (sans
EXPLAIN) puis une fois avec EXPLAIN. Notez les rsultats.

Question 20 Essayez le mme enchanement doprations avec la requte sur la colonne pt. Que se
passe-t-il ?

10/06/2015

23

Question 21 Essayez le mme enchanement doprations avec la requte sur la colonne geom. Que se
passe-t-il ?

Question 22 Quelles sont vos conclusions ?

10/06/2015

24

9 Webographie
9.1 PostGreSQL
http://docs.postgresql.fr/8.4/
(le point dentre)
http://docs.postgresql.fr/8.4/sql.html
(les chapitres sur le langage SQL)
http://docs.postgresql.fr/8.4/server-programming.html
(les chapitres sur la programmation serveur : PL/pgSQL, triggers, etc.)

9.2 PostGIS
La documentation officielle, en anglais :
* http://postgis.refractions.net/docs/
(le point dentre)
* http://postgis.refractions.net/docs/ch04.html
(le guide utilisateur de PostGIS)
La traduction de la documentation en franais :
* http://www.postgis.fr/node/156
(le point dentre)
Une traduction est toujours un peu en retard. Au 31 octobre 2009, la partie 4.2.5. Ensuring
OpenGIS compliancy of geometries nest pas traduite. On la trouvera en anglais ici :
* http://postgis.refractions.net/docs/ch04.html#OGC_Validity
Le cours de David Techer :
* http://www.davidgis.fr/documentation/win32/html/index.html
(le point dentre)
* http://www.davidgis.fr/documentation/win32/html/ch05.html
(le tutorial)
* http://www.davidgis.fr/documentation/win32/html/ch06.html
(des exemples)

10/06/2015

25

10 A rendre
Question 0 Identification :

Nom :
Prnom :
Question 1 Liste des colonnes avec leur type :

timestamp without time zone


latitude

Real

longitude

Question 2 Instruction SQL fixant la valeur par dfaut de la colonne id :

Question 3 - Dure maximale du script PHP :

Comment allonger la dure maximale ?

Requte Google pour arriver cette rponse :

Question 4 UPDATE sur la colonne pt :

10/06/2015

26

Question 5 Instruction crant la colonne geom :

Question 6 UPDATE sur la colonne geom :

Question 7 Quel est le nom de lobjet cr par loption -I ?

Question 8 Une requte utilisant la fonction count() :

Requte :

Rsultat :

Question 9 Deux requtes utilisant les clauses ORDER BY et LIMIT :

Requte pour la magnitude du tremblement de terre de plus forte magnitude :


Rsultat :

Requte pour la profondeur du tremblement de terre le plus profond :


Rsultat :

Question 10 La vue qui donne les 200 tremblements de terre de plus forte magnitude :

10/06/2015

27

Question 11 - la requte qui dtermine la magnitude du plus faible tremblement de terre de cette vue :

Question 12 Jointure dans un SELECT la requte modifie :

Question 13 nombre de tremblements de terre trouvs

Pour la requte avec WITHIN :


Pour la requte avec NOT WITHIN :

Question 14 transformation en requte de mise jour :

Question 15 analyse dtaille de la requte

10/06/2015

28

Question 16 Combien dobjets maintenant dans la table tdt ?

Question 17 Trois requtes SELECT WHERE :

- sur latitude et longitude :


- sur pt :
- sur geom :

Question 18 A quoi sert linstruction EXPLAIN ?

Question 19 Comparaison des index pour une requte sur les colonnes latitude et longitude :

Requte sur les colonnes latitude et longitude


Temps dexcution
(en ms)

EXPLAIN

sans index
moyenne :

avec btree
moyenne :
Avec btree
et gist

moyenne :

avec gist
(sans btree)
moyenne :

Question 20 - Mme chose pour la colonne pt :

10/06/2015

29

Requte sur la colonne pt


Temps dexcution
(en ms)

EXPLAIN

sans index
moyenne :

avec btree
moyenne :
Avec btree
et gist

moyenne :

avec gist
(sans btree)

moyenne :

Question 21 - Mme chose pour la colonne geom :

Requte sur les colonnes latitude et longitude


Temps dexcution
(en ms)

EXPLAIN

sans index
moyenne :

avec btree
moyenne :
Avec btree
et gist

moyenne :

avec gist
(sans btree)
moyenne :

Question 22 Quelles sont vos conclusions ?

10/06/2015

30

10/06/2015

31