web-dev-qa-db-fra.com

Différence entre les requêtes de filtrage dans JOIN et WHERE?

En SQL, j'essaie de filtrer les résultats en fonction d'un ID et je me demande s'il y a une différence logique entre

SELECT value 
FROM table1 
JOIN table2 ON table1.id = table2.id 
WHERE table1.id = 1

et

SELECT value 
FROM table1 
JOIN table2 ON table1.id = table2.id AND table1.id = 1

Pour moi, il semble que la logique soit différente bien que vous obtiendrez toujours le même ensemble de résultats, mais je me demandais s'il y avait des conditions dans lesquelles vous obtiendriez deux ensembles de résultats différents (ou renverraient-ils toujours exactement les deux mêmes ensembles de résultats )

29
warsong

La réponse est [~ # ~] pas de différence [~ # ~] , mais:

Je préférerai toujours faire ce qui suit.

  • Gardez toujours la Conditions de jointure dans la clause ON
  • Mettez toujours le filtre dans la clause where

Cela rend la requête plus lisible .

Je vais donc utiliser cette requête:

SELECT value
FROM table1
INNER JOIN table2
        ON table1.id = table2.id
WHERE table1.id = 1

Cependant, lorsque vous utilisez OUTER JOIN'S il y a une grande différence à garder le filtre dans les conditions ON et Where.

Traitement logique des requêtes

La liste suivante contient une forme générale de requête, ainsi que des numéros d'étape attribués selon l'ordre dans lequel les différentes clauses sont traitées logiquement.

(5) SELECT (5-2) DISTINCT (5-3) TOP(<top_specification>) (5-1) <select_list>
(1) FROM (1-J) <left_table> <join_type> JOIN <right_table> ON <on_predicate>
| (1-A) <left_table> <apply_type> APPLY <right_table_expression> AS <alias>
| (1-P) <left_table> PIVOT(<pivot_specification>) AS <alias>
| (1-U) <left_table> UNPIVOT(<unpivot_specification>) AS <alias>
(2) WHERE <where_predicate>
(3) GROUP BY <group_by_specification>
(4) HAVING <having_predicate>
(6) ORDER BY <order_by_list>;

Diagramme de flux de traitement logique

Enter image description here

  • (1) FROM: la phase FROM identifie les tables source de la requête et traite les opérateurs de table. Chaque opérateur de table applique une série de sous-phases. Par exemple, les phases impliquées dans une jointure sont (1-J1) un produit cartésien, (1-J2) ON Filter, (1-J3) Add Outer Rows. La phase FROM génère la table virtuelle VT1.

  • (1-J1) Produit cartésien: Cette phase effectue un produit cartésien (jointure croisée) entre les deux tables impliquées dans l'opérateur de table, générant VT1-J1.

  • (1-J2) Filtre ON : cette phase filtre les lignes de VT1-J1 en fonction du prédicat qui apparaît dans la clause ON (<on_predicate>) . Seules les lignes pour lesquelles le prédicat est évalué comme VRAI sont insérées dans VT1-J2.
  • (1-J3) Ajouter des lignes externes : si OUTER JOIN est spécifié (par opposition à CROSS JOIN ou INNER JOIN), des lignes de la ou des tables préservées pour lesquels aucune correspondance n'a été trouvée sont ajoutés aux lignes de VT1-J2 en tant que lignes externes, générant VT1-J3.
  • (2) [~ # ~] où [~ # ~] : cette phase filtre les lignes de VT1 en fonction du prédicat qui apparaît dans la clause WHERE (). Seules les lignes pour lesquelles le prédicat est évalué comme VRAI sont insérées dans VT2.
  • (3) GROUP BY: cette phase organise les lignes de VT2 en groupes en fonction de la liste de colonnes spécifiée dans la clause GROUP BY, générant VT3. En fin de compte, il y aura une ligne de résultats par groupe.
  • (4) HAVING: cette phase filtre les groupes de VT3 en fonction du prédicat qui apparaît dans la clause HAVING (<having_predicate>). Seuls les groupes pour lesquels le prédicat est évalué comme VRAI sont insérés dans VT4.
  • (5) SELECT: cette phase traite les éléments de la clause SELECT, générant VT5.
  • (5-1) Évaluer les expressions: cette phase évalue les expressions de la liste SELECT, générant VT5-1.
  • (5-2) DISTINCT: Cette phase supprime les lignes en double de VT5-1, générant VT5-2.
  • (5-3) TOP: cette phase filtre le nombre ou le pourcentage supérieur spécifié de lignes de VT5-2 en fonction de l'ordre logique défini par la clause ORDER BY, générant la table VT5-3.
  • (6) ORDER BY: Cette phase trie les lignes de VT5-3 selon la liste de colonnes spécifiée dans la clause ORDER BY, générant le curseur VC6.

Il fait référence à cet excellent lien.

39
Pரதீப்

Bien qu'il n'y ait aucune différence lors de l'utilisation de INNER JOINS, comme l'a souligné VR46, il existe une différence significative lors de l'utilisation de OUTER JOINS et de l'évaluation d'une valeur dans le deuxième tableau (pour les jointures de gauche - première table pour les jointures droites). Considérez la configuration suivante:

DECLARE @Table1 TABLE ([ID] int)
DECLARE @Table2 TABLE ([Table1ID] int, [Value] varchar(50))

INSERT INTO @Table1
VALUES
(1),
(2),
(3)

INSERT INTO @Table2
VALUES
(1, 'test'),
(1, 'hello'),
(2, 'goodbye')

Si nous le sélectionnons en utilisant une jointure externe gauche et mettons une condition dans la clause where:

SELECT * FROM @Table1 T1
LEFT OUTER JOIN @Table2 T2
    ON T1.ID = T2.Table1ID
WHERE T2.Table1ID = 1

Nous obtenons les résultats suivants:

ID          Table1ID    Value
----------- ----------- --------------------------------------------------
1           1           test
1           1           hello

Cela est dû au fait que la clause where limite l'ensemble de résultats, nous n'incluons donc que les enregistrements de table1 qui ont un ID de 1. Cependant, si nous déplaçons la condition dans la clause on:

SELECT * FROM @Table1 T1
LEFT OUTER JOIN @Table2 T2
    ON T1.ID = T2.Table1ID
    AND T2.Table1ID = 1

Nous obtenons les résultats suivants:

ID          Table1ID    Value
----------- ----------- --------------------------------------------------
1           1           test
1           1           hello
2           NULL        NULL
3           NULL        NULL

En effet, nous ne filtrons plus l'ensemble de résultats par l'ID 1 de la table1 - nous filtrons plutôt le JOIN. Ainsi, même si l'ID de table1 de 2 a une correspondance dans la deuxième table, il est exclu de la jointure - mais PAS l'ensemble de résultats (d'où les valeurs nulles).

Ainsi, pour les jointures internes, cela n'a pas d'importance, mais vous devez le conserver dans la clause where pour plus de lisibilité et de cohérence. Cependant, pour les jointures externes, vous devez être conscient que cela importe où vous placez la condition car cela affectera votre jeu de résultats.

12
Stan Shaw

Je pense que la réponse marquée "droite" n'est pas correcte. Pourquoi? J'essaie d'expliquer:

Nous avons une opinion

"Gardez toujours la clause Join Conditions in ON Mettez toujours le filtre dans la clause where"

Et c'est faux. Si vous êtes dans la jointure interne, mettez à chaque fois les paramètres de filtre dans la clause ON, pas dans où. Vous demandez pourquoi? Essayez d'imaginer une requête complexe avec un total de 10 tables (c'est-à-dire que chaque table a 10 000 enregistrements), avec la clause WHERE complexe (par exemple, les fonctions ou les calculs utilisés). Si vous placez des critères de filtrage dans la clause ON, JOINS entre ces 10 tables ne se produit pas, la clause WHERE ne sera pas exécutée du tout. Dans ce cas, vous n'effectuez pas 10000 ^ 10 calculs dans la clause WHERE. Cela a du sens, ne pas placer les paramètres de filtrage dans la clause WHERE uniquement.

3
Juozas