carroyées, produire une carte de stock, de ratio, de discontinuités des frontières
Les liens suivants sont de qualité et expliquent bien les différents types de jointure. Une base essentielle à comprendre avant de poursuivre le module, qui se sert de ces notions dans des montages de plus en plus complexes :
Une jointure implicite est réalisée en indiquant plusieurs tables dans la clause FROM sans opérateur JOIN . C’est conceptuellement une jointure croisée (CROSS JOIN )
La première requête (jointure implicite) est équivalente à la seconde (explicite avec CROSS JOIN ) :
SELECT * FROM table1, table2
SELECT * FROM table1 CROSS JOIN table2
On peut ajouter une condition dans le WHERE limitant la jointure, dans ce cas il s’agit conceptuellement d’une jointure INNER JOIN . De ce fait, les 2 requêtes suivantes sont équivalentes :
SELECT * FROM table1, table2 WHERE table1.id = table2.id
SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id
On notera que pour ces jointures, on peut permuter table1 et table2 sans changer le résultat, mis à part l’ordre de tri des enregistrements et des colonnes.
Soient les tables products et tags suivantes :
CREATE TABLE products
(
id serial,
name character varying,
CONSTRAINT products_pkey PRIMARY KEY (id)
)
CREATE TABLE tags
(
product_id integer NOT NULL,
tag character varying NOT NULL,
CONSTRAINT tags_pkey PRIMARY KEY (product_id, tag),
CONSTRAINT tags_product_id_fkey FOREIGN KEY (product_id)
REFERENCES products (id)
)
Insérer les contenus suivants, respectivement dans les tables products et tags :
"1";"poirot" "2";"poire" "3";"orange" "4";"carotte" "5";"radis"
1;"légume" 1;"tige" 2;"fruit" 3;"fruit" 4;"légume" 4;"racine"
Si la jointure INNER
multiplie
les tables entres elles, en revanche elle ne laisse pas passer les enregistrements qui n’ont pas leur correspondance dans l’autre table. Dans bon nombre de cas, on sert de la jointure comme pour associer
(on dit aussi apparier
) une table d’attributs à une table de départ. On souhaite alors qu’en l’absence d’attributs, un enregistrement de la table de départ soit préservé, quitte à mettre les champs sans correspondance à NULL
.
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id
Dans cette requête, tous les enregistrements de table1 seront présents à la sortie, bien que répétés pour ceux qui disposent de plusieurs équivalents (d’après id ) dans table2
Permuter table1 et table2 ne produit pas le même résultat. La table de gauche est première et celle de droite seconde.
En Français : On requête la table table1 en y associant table2 par correspondance sur le champ id .
Remplacer LEFT par RIGHT rend primaire la table de droite, celle dont tous les enregistrements seront tous conservés. Ces 2 requêtes sont équivalentes :
SELECT col1, col2 FROM table1 LEFT JOIN table2 ON table1.id = table2.id
SELECT col1, col2 FROM table2 RIGHT JOIN table1 ON table1.id = table2.id
Effectuer plusieurs jointures implicites est facile :
SELECT * FROM table1, table2, table 3
SELECT * FROM table1, table2, table 3 WHERE table1.id = table2.id AND table2.id = table3.id
Dans cet exemple, à table1 est jointe table2 , et enfin, à ce résultat intermédiaire, est jointe table3 : cet ordre (de gauche à droite) détermine l’ordre des colonnes et des enregistrements, mais à part cet ce tri le résultat est le même : la jointure CROSS est commutative et associative .
Il en va de même pour les jointures CROSS et INNER explicites :
SELECT * FROM table1 CROSS JOIN table2 CROSS JOIN table 3
Les jointures INNER sont également commutatives et associatives (leur ordre n’importe pas) :
SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id
INNER JOIN table3 ON table2.id = table3.id
Les jointures OUTER (c’est-à-dire LEFT , RIGHT ou FULL ) par contre, ne sont pas commutatives . Il faut donc bien partir de LA table à requêter (ce qu’on cherche en premier lieu), puis y joindre les autres tables :
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id
LEFT JOIN table3 ON table2.id = table3.id
Mixer des jointures INNER et LEFT (ou autres) est possible. Les jointures sont effectuées de gauche à droite.
SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id
LEFT JOIN table3 ON table2.id = table3.id
L’agrégation a lieu après les jointures (le FROM est évalué) mais avant évaluation de la clause SELECT . Dans cet exemple :
SELECT age FROM table1 GROUP BY age
Les enregistrements de table1
sont groupés par age
. Seuls les groupes peuvent sortir
dans le résultat. On ne pourrait pas écrire
SELECT id, age
car id
n’est pas agrégé par le groupe. En revanche on pourrait écrire ceci :
SELECT age, count(id) FROM table1 GROUP BY age
Car on ne peut inclure dans le SELECT que :
Le sous-SELECT est un SELECT utilisé en tant que table dans la clause FROM d’une requête SELECT . Ces 2 requêtes sont équivalents :
SELECT nom FROM (SELECT id, nom FROM table1 WHERE nom LIKE ’A%’) AS q WHERE id > 10
SELECT nom FROM table1 WHERE nom LIKE ’A%’ AND id > 10
La technique devient indispensable pour effectuer des jointures d’agrégations , c’est-à-dire une agrégation (SELECT [...] GROUP BY [...] ) elle-même jointe à une table (voire une autre agrégation...). Exemple :
SELECT FROM
(SELECT nom, count(id) AS id FROM table1 GROUP BY nom) AS sub
LEFT JOIN table2 ON sub.id = table2.id
Le mot-clef ON permet, si on y regarde, demande une expression booléenne (qui s’évalue en vrai ou faux ). Cette expression peut être autre chose q’une égalité d’identifiants numériques. Par exemple :
SELECT * FROM table1 INNER JOIN table2 ON table1.id > table2.id
SELECT * FROM table1 INNER JOIN table2 ON (table1.id + 1) > table2.id
Utiliser des expressions prend tout son sens avec les aggrégations (qui permettent ensuite de réduire ce qui a été développé avec l’expression).
Plus généralement, l’expression indique le mode de relation qu’on souhaite entre les 2 tables ainsi jointes. Spatialement, cela permet de récupérer par exemple la liste des points d’intérêts et pour chacun le nom de la commune dans laquelle il se trouve
, avec une requête du type :
SELECT poi.*, communes.nom AS commune
FROM poi LEFT JOIN communes ON ST_Within(poi.geom, communes.geom)
À partir de la table etablissements_culturels importée du module Import-Export :
De la même façon que la fonction count()
aggrège un groupe de valeurs en une valeur unique, certaines fonctions PostGIS
fonctionnent en mode aggrégation
. Notamment :
CREATE TABLE departements AS ... requête SELECT telle quelle ...
Nous allons a présent créer une carte des départements de France avec un cercle proportionnel sur chaque centroïde représentant le nombre de d’établissements culturels dans le département.
Nous allons reprendre les carroyages de la table r_rfl09_laea1000 importée dans le module Import-Export pour produire une nouvelle table, r_rfl09_cut_dpt , où les carreaux à cheval sur 2 départements ou plus sont coupés en morceaux qui épousent la frontière.
transformer r_rfl09_laea1000 dans le SRID de departementsou bien
transformer les departements dans le SRID de r_rfl09_laea1000 ?
Comment penser la jointure ?
Les départements servent à découper les carreaux
Pour chaque carreau , on produit autant de bouts de carreaux que de départements qu’il intersecte
Chaque bout de carreau est l’intersection entre un carreau et un département
Écrire la jointure avec les champs SELECT suivants :
Indices :
impensabled’exécuter la jointure d’intersections sans avoir au préalable créé les index spatiaux sur les champs géométriques intersectés
Créer la table en exécutant la requête précédée par CREATE TABLE r_rfl09_cut_dpt AS
Reprendre la requête précédente en groupant par departements.code_dpt pour produire la table departements_popul listant les départements avec les colonnes :
L’applat de couleurs (chloroplethe) n’est pas un mode de représentation cartographique adapté à un stock, car l’importance du phénomène serait doublement représenté (variable de couleur et taille de la surface). Il s’agit là de règles de sémiologie. Pour des stocks (de population ou autre), il convient d’utiliser des symboles proportionnels centrés sur le centroïde du territoire dont ils représentent la variable.
Nous allons donc utiliser produire une carte avec 2 couches :
Sachant que :
De la même façon que pour CB , créer la vue departements_popul_ratio reprenant les colonnes de departements_popul en ajoutant la colonne popul_densite représentant la densité de population en nombre d’habitants par kilomètre-carré dans la projection Lambert 93 .
L’intersection entre 2 polygones ne produit pas toujours un polygone. Si les polygones se touchent (au sens de ST_Touches ), alors l’intersection produit une ligne, celle que partagent les polygones. Quant à 2 polygones qui se touchent sur un seul sommet, leur intersection produit un point.
Il est possible d’effectuer une jointure d’une table avec elle-même en précisant des alias différents, comme ceci :
SELECT [...] FROM table t1 INNER JOIN table t2 ON [.. expression impliquant t1 et t2 ..]
Une couche territoriale (où aucun territoire ne chevauche un autre) peut être jointe à elle-même sur la condition ST_Touches (t1.geom, t2.geom) pour récupérer la ligne de frontière avec l’expression ST_Intersection (t1.geom, t2.geom) .
Exécuter la requête suivante pour générer les frontères des departements :
CREATE TABLE departements_frontieres as
SELECT
a.code_dpt || ’-’ || b.code_dpt AS id,
a.code_dpt AS a, b.code_dpt AS b,
ST_Intersection(a.geom, b.geom)::geometry(Geometry, 4326) AS frontiere
FROM departements a
INNER JOIN departements b ON ST_Touches(a.geom, b.geom)
Puis créer la clef primaire :
ALTER TABLE departements_frontieres ADD PRIMARY KEY (id);
Et l’index spatial :
CREATE INDEX ON departements_frontieres USING gist (frontiere);
Puis l’afficher dans QGIS (couleur libre)
À partir de la table departements_frontieres , écrire la requête pour produire la vue departements_frontieres_popul_disc avec la colonne supplémentaire disc valant le delta sur zéro du rapport des densités des départements de part et d’autre de la frontière concernée.
Puis dans QGIS , produire la carte de discontinuités avec 2 couches :