Les instructions suivantes donnent le même résultat (l'une utilise on
et l'autre utilise where
):
mysql> select * from gifts INNER JOIN sentGifts ON gifts.giftID = sentGifts.giftID;
mysql> select * from gifts INNER JOIN sentGifts WHERE gifts.giftID = sentGifts.giftID;
Je ne peux voir que dans le cas d'une jointure externe gauche trouver les cas "inégalés":
(pour découvrir les cadeaux qui n'ont jamais été envoyés par personne)
mysql> select name from gifts LEFT OUTER JOIN sentgifts
ON gifts.giftID = sentgifts.giftID
WHERE sentgifts.giftID IS NULL;
Dans ce cas, il utilise d'abord on
, puis where
. Est-ce que on
fait d'abord la correspondance, puis where
fait le filtrage "secondaire"? Ou existe-t-il une règle plus générale d'utilisation de on
par rapport à where
? Merci.
WHERE
fait partie de la requête SELECT
dans son ensemble, ON
fait partie de chaque jointure individuelle.
ON
ne peut faire référence qu'aux champs des tables précédemment utilisées.
Lorsqu'il n'y a pas de correspondance réelle avec un enregistrement dans le tableau de gauche, LEFT JOIN
renvoie un enregistrement de la table de droite avec tous les champs définis sur NULLS
. WHERE
clause évalue et filtre ensuite cela.
Dans votre requête, seuls les enregistrements de gifts
sans correspondance dans 'sentgifts' sont retournés.
Voici l'exemple
gifts
1 Teddy bear
2 Flowers
sentgifts
1 Alice
1 Bob
---
SELECT *
FROM gifts g
LEFT JOIN
sentgifts sg
ON g.giftID = sg.giftID
---
1 Teddy bear 1 Alice
1 Teddy bear 1 Bob
2 Flowers NULL NULL -- no match in sentgifts
---
SELECT *
FROM gifts g
LEFT JOIN
sentgifts sg
ON g.giftID = sg.giftID
WHERE sg.giftID IS NULL
---
2 Flowers NULL NULL -- no match in sentgifts
Comme vous pouvez le voir, aucune correspondance réelle ne peut laisser un NULL
dans sentgifts.id
, donc seuls les cadeaux qui n'ont jamais été envoyés sont retournés.
La clause ON
définit la relation entre les tables.
La clause WHERE
décrit les lignes qui vous intéressent.
Plusieurs fois, vous pouvez les échanger et obtenir toujours le même résultat, mais ce n'est pas toujours le cas avec une jointure externe gauche.
- Si la clause
ON
échoue, vous obtenez toujours une ligne avec des colonnes de la table de gauche mais avec des valeurs nulles dans les colonnes de la table de droite.- Si la clause
WHERE
échoue, vous n'obtiendrez pas du tout cette ligne.
Lors de l'utilisation de INNER JOIN
, ON
et WHERE
auront le même résultat. Donc,
select *
from Table1 t1
inner join Table2 t2 on t1.id = t2.id
where t1.Name = 'John'
aura exactement la même sortie que
select *
from Table1 t1
inner join Table2 t2 on t1.id = t2.id
and t1.Name = 'John'
Comme vous l'avez noté, ce n'est pas le cas lors de l'utilisation de OUTER JOIN
. Le plan de requête qui est construit dépend de la plate-forme de base de données ainsi que des spécificités de la requête, et est susceptible de changer, donc la prise de décisions sur cette seule base ne donnera pas un plan de requête garanti.
En règle générale, vous devez utiliser des colonnes qui joignent vos tables dans des clauses ON
et des colonnes qui sont utilisées pour le filtrage dans des clauses WHERE
. Cela offre la meilleure lisibilité.
Bien que les résultats soient les mêmes, la valeur "ON" effectue la jointure en premier, puis récupère les données de l'ensemble joint. La récupération est plus rapide et la charge est moindre. Mais en utilisant 'WHERE', les deux jeux de résultats sont récupérés en premier, puis appliquent la condition. Vous savez donc ce qui est préféré.
En effet, ON remplace chaque champ qui ne satisfait pas à sa condition par un NULL. Étant donné l'exemple de @Quassnoi
gifts
1 Teddy bear
2 Flowers
sentgifts
1 Alice
1 Bob
---
SELECT *
FROM gifts g
LEFT JOIN
sentgifts sg
ON g.giftID = sg.giftID
---
Les permutations LEFT JOIN auraient été calculées pour les collections suivantes s'il n'y avait pas de condition ON:
{ 'Teddy bear': {'ALICE', 'Bob'}, 'Flowers': {'ALICE', 'Bob'} }
avec le g.giftID = sg.giftID
Condition ON, ce sont les collections qui seront utilisées pour créer les permutations:
{ 'Teddy bear': {'ALICE', 'Bob'}, 'Flowers': {NULL, NULL} }
qui est en effet:
{ 'Teddy bear': {'ALICE', 'Bob'}, 'Flowers': {NULL} }
et se traduit donc par la GAUCHE JOIN de:
Teddy bear Alice
Teddy bear Bob
Flowers NULL
et pour une FULL OUTER JOIN, vous auriez:
{ 'Teddy bear': {'ALICE', 'Bob'}, 'Flowers': {NULL} }
pour LEFT JOIN et { 'ALICE': {'Teddy bear', NULL}, 'Flowers': {'Teddy bear', NULL} }
pour RIGHT JOIN:
Teddy bear Alice
Teddy bear Bob
Flowers NULL
Si vous aviez également une condition telle que ON g.giftID = 1
ce serait
{ NULL: {'ALICE', 'Bob'}, 'Flowers': {NULL} }
qui pour LEFT JOIN se traduirait par
Flowers NULL
et pour une FULL OUTER JOIN entraînerait { NULL: {'ALICE', 'Bob'}, 'Flowers': {NULL} }
pour LEFT JOIN et { 'ALICE': {NULL, NULL}, 'Flowers': {NULL, NULL} }
pour RIGHT JOIN
NULL Alice
NULL Bob
Flowers NULL
Remarque MySQL n'a pas de FULL OUTER JOIN et vous devez appliquer UNION à LEFT JOIN et RIGHT JOIN