web-dev-qa-db-fra.com

Dans SQL / MySQL, quelle est la différence entre "ON" et "WHERE" dans une instruction join?

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.

44

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.

48
Quassnoi

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.
49
Mark Byers

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é.

14
RedFilter

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é.

3
Kangkan
  • ON est appliqué à l'ensemble utilisé pour créer les permutations de chaque enregistrement dans le cadre de l'opération JOIN
  • WHERE spécifie le filtre appliqué après l'opération JOIN

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

2
Hou