Jusqu'ici, nos requêtes avaient seulement consulté une table à la fois. Les
requêtes peuvent accéder à plusieurs tables en même temps ou accéder à la
même table de façon à ce que plusieurs lignes de la table soient traitées
en même temps. Une requête qui consulte plusieurs lignes de la même ou de
différentes tables en même temps est appelée requête de
jointure. Comme exemple, supposez que vous souhaitiez
comparer la colonne ville
de chaque ligne de la
table temps
avec la colonne
nom
de toutes les lignes de la table
villes
et que vous choisissiez les paires de lignes
où ces valeurs correspondent.
Ceci est uniquement un modèle conceptuel. La jointure est habituellement exécutée d'une manière plus efficace que la comparaison de chaque paire de lignes, mais c'est invisible pour l'utilisateur.
Ceci sera accompli avec la requête suivante :
SELECT * FROM temps, villes WHERE ville = nom;
ville | t_basse | t_haute | prcp | date | nom | emplacement ---------------+---------+---------+------+------------+---------------+------------- San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53) San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53) (2 rows)
Deux remarques à propos du résultat :
Il n'y a pas de lignes pour la ville de Hayward dans le résultat. C'est
parce qu'il n'y a aucune entrée correspondante dans la table
villes
pour Hayward, donc la jointure ignore
les lignes n'ayant pas de correspondance avec la table
temps
. Nous verrons rapidement comment cela
peut être résolu.
Il y a deux colonnes contenant le nom des villes. C'est correct, car les
listes des colonnes des tables temps
et
villes
sont concaténées. En pratique, ceci est
indésirable, vous voudrez probablement lister les colonnes explicitement
plutôt que d'utiliser *
:
SELECT ville, t_basse, t_haute, prcp, date, emplacement FROM temps, villes WHERE ville = nom;
Exercice :
Essayez de déterminer la sémantique de cette requête quand la clause
WHERE
est omise.
Puisque toutes les colonnes ont un nom différent, l'analyseur a automatiquement trouvé à quelle table elles appartiennent. Si des noms de colonnes sont communs entre les deux tables, vous aurez besoin de qualifier les noms des colonnes pour préciser celles dont vous parlez. Par exemple :
SELECT temps.ville, temps.t_basse, temps.t_haute, temps.prcp, temps.date, villes.emplacement FROM temps, villes WHERE villes.nom = temps.ville;
La qualification des noms de colonnes dans une requête de jointure est fréquemment considérée comme une bonne pratique. Cela évite l'échec de la requête si un nom de colonne dupliqué est ajouté plus tard dans une des tables.
Les requêtes de jointure vues jusqu'ici peuvent aussi être écrites sous une autre forme :
SELECT * FROM temps INNER JOIN villes ON (temps.ville = villes.nom);
Cette syntaxe n'est pas aussi couramment utilisée que les précédentes, mais nous la montrons ici pour vous aider à comprendre les sujets suivants.
Maintenant, nous allons essayer de comprendre comment nous pouvons avoir
les entrées de Hayward. Nous voulons que la requête parcoure la table
temps
et que, pour chaque ligne, elle trouve la
(ou les) ligne(s) de villes
correspondante(s). Si
aucune ligne correspondante n'est trouvée, nous voulons que les valeurs des
colonnes de la table villes
soient remplacées par
des « valeurs vides ». Ce genre de requêtes est appelé
jointure externe (outer join). (Les jointures que
nous avons vues jusqu'ici sont des jointures internes -- inner joins).
La commande ressemble à cela :
SELECT * FROM temps LEFT OUTER JOIN villes ON (temps.ville = villes.nom); ville | t_basse | t_haute | prcp | date | nom | emplacement ---------------+---------+---------+------+------------+---------------+------------- Hayward | 37 | 54 | | 1994-11-29 | | San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53) San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53) (3 rows)
Cette requête est appelée une jointure externe à gauche (left outer join) parce que la table mentionnée à la gauche de l'opérateur de jointure aura au moins une fois ses lignes dans le résultat, tandis que la table sur la droite aura seulement les lignes qui correspondent à des lignes de la table de gauche. Lors de l'affichage d'une ligne de la table de gauche pour laquelle il n'y a pas de correspondance dans la table de droite, des valeurs vides (appelées NULL) sont utilisées pour les colonnes de la table de droite.
Exercice : Il existe aussi des jointures externes à droite et des jointures externes complètes. Essayez de trouver ce qu'elles font.
Nous pouvons également joindre une table avec elle-même. Ceci est appelé
une jointure réflexive. Comme exemple, supposons
que nous voulions trouver toutes les entrées de temps qui sont dans un
intervalle de températures d'autres entrées de temps. Nous avons donc besoin
de comparer les colonnes t_basse
et
t_haute
de chaque ligne de
temps
aux colonnes
t_basse
et
t_haute
de toutes les autres lignes de
temps
. Nous pouvons faire cela avec la requête
suivante :
SELECT T1.ville, T1.t_basse AS bas, T1.t_haute AS haut, T2.ville, T2.t_basse AS bas, T2.t_haute AS haus FROM temps T1, temps T2 WHERE T1.t_basse < T2.t_basse AND T1.t_haute > T2.t_haute; ville | bas | haut | ville | bas | haut ----------------+-----+------+---------------+-----+------ San Francisco | 43 | 57 | San Francisco | 46 | 50 Hayward | 37 | 54 | San Francisco | 46 | 50 (2 rows)
Dans cet exemple, nous avons renommé la table temps en T1
et en T2
pour être capables de distinguer respectivement
le côté gauche et le côté droit de la jointure. Vous pouvez aussi utiliser
ce genre d'alias dans d'autres requêtes pour économiser de la frappe,
c'est-à-dire :
SELECT * FROM temps t, villes v WHERE t.ville = v.nom;
Vous rencontrerez ce genre d'abréviation assez fréquemment.