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. Les requêtes qui accèdent à plusieurs tables
(ou plusieurs fois la même table) sont appelées des requêtes de
jointure. Elles combinent les lignes d'une table
avec les lignes d'une deuxième table, avec une expression indiquant
comment réaliser la jointure entre ces lignes. Par exemple, pour renvoyer
toutes les lignes de la table temps avec l'emplacement de la ville
associée, la base de données doit 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.[4]
Ceci sera accompli avec la requête suivante :
SELECT * FROM temps JOIN villes ON 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 JOIN villes ON ville = nom;
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 JOIN villes ON 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 cette forme :
SELECT * FROM temps, villes WHERE ville = nom;
Cette syntaxe date d'avant la syntaxe
JOIN
/ON
, qui a été introduite dans
SQL-92. Les tables sont simplement listées dans la clause
FROM
, et l'expression de comparaison est ajoutée dans
la clause WHERE
. Les résultats de l'ancienne syntaxe
implicite et de la nouvelle syntaxe explicite
JOIN
/ON
sont identiques. Cependant,
pour celui qui lit la requête, la syntaxe explicite est plus facile à
comprendre : la condition de jointure est introduite par son propre
mot clé alors qu'auparavant, la condition était mélangée dans la clause
WHERE
avec les autres conditions.
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 JOIN temps T2 ON 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 JOIN villes v ON t.ville = v.nom;
Vous rencontrerez ce genre d'abréviation assez fréquemment.
[4] 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.