web-dev-qa-db-fra.com

Jointure SQL: clause Where vs clause

Après l'avoir lu, il s'agit et non d'une copie de Jointures SQL explicites ou implicites . La réponse peut être liée (ou même identique) mais la question est différente.


Quelle est la différence et que devrait-il y avoir dans chacun?

Si je comprends bien la théorie, l'optimiseur de requêtes devrait pouvoir utiliser les deux de manière interchangeable.

587
BCS

Ce n'est pas la même chose.

Considérez ces requêtes:

SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID
WHERE Orders.ID = 12345

et

SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID 
    AND Orders.ID = 12345

Le premier renverra une commande et ses lignes, le cas échéant, pour le numéro de commande 12345. La seconde renverra toutes les commandes, mais seule la commande 12345 sera associée à des lignes.

Avec un INNER JOIN, les clauses sont effectivement équivalentes. Cependant, ce n’est pas parce qu’elles sont fonctionnellement identiques, en ce qu’elles produisent les mêmes résultats, que les deux types de clauses ont la même signification sémantique.

762
Joel Coehoorn
  • N'a pas d'importance pour les jointures internes
  • Questions pour les jointures externes

    une. Clause WHERE: After rejoindre. Les enregistrements seront filtrés après la jointure.

    b. ON clause - Before rejoindre. Les enregistrements (de la table de droite) seront filtrés avant l'adhésion. Cela peut finir par être nul dans le résultat (puisque OUTER join).



Exemple: Considérez les tableaux ci-dessous:

    1. documents:
     | id    | name        |
     --------|-------------|
     | 1     | Document1   |
     | 2     | Document2   |
     | 3     | Document3   |
     | 4     | Document4   |
     | 5     | Document5   |


    2. downloads:
     | id   | document_id   | username |
     |------|---------------|----------|
     | 1    | 1             | sandeep  |
     | 2    | 1             | simi     |
     | 3    | 2             | sandeep  |
     | 4    | 2             | reya     |
     | 5    | 3             | simi     |

a) Dans la clause WHERE:

  SELECT documents.name, downloads.id
    FROM documents
    LEFT OUTER JOIN downloads
      ON documents.id = downloads.document_id
    WHERE username = 'sandeep'

 For above query the intermediate join table will look like this.

    | id(from documents) | name         | id (from downloads) | document_id | username |
    |--------------------|--------------|---------------------|-------------|----------|
    | 1                  | Document1    | 1                   | 1           | sandeep  |
    | 1                  | Document1    | 2                   | 1           | simi     |
    | 2                  | Document2    | 3                   | 2           | sandeep  |
    | 2                  | Document2    | 4                   | 2           | reya     |
    | 3                  | Document3    | 5                   | 3           | simi     |
    | 4                  | Document4    | NULL                | NULL        | NULL     |
    | 5                  | Document5    | NULL                | NULL        | NULL     |

  After applying the `WHERE` clause and selecting the listed attributes, the result will be: 

   | name         | id |
   |--------------|----|
   | Document1    | 1  |
   | Document2    | 3  | 

b) Dans la clause JOIN

  SELECT documents.name, downloads.id
  FROM documents
    LEFT OUTER JOIN downloads
      ON documents.id = downloads.document_id
        AND username = 'sandeep'

For above query the intermediate join table will look like this.

    | id(from documents) | name         | id (from downloads) | document_id | username |
    |--------------------|--------------|---------------------|-------------|----------|
    | 1                  | Document1    | 1                   | 1           | sandeep  |
    | 2                  | Document2    | 3                   | 2           | sandeep  |
    | 3                  | Document3    | NULL                | NULL        | NULL     |
    | 4                  | Document4    | NULL                | NULL        | NULL     |
    | 5                  | Document5    | NULL                | NULL        | NULL     |

Notice how the rows in `documents` that did not match both the conditions are populated with `NULL` values.

After Selecting the listed attributes, the result will be: 

   | name       | id   |
   |------------|------|
   |  Document1 | 1    |
   |  Document2 | 3    | 
   |  Document3 | NULL |
   |  Document4 | NULL | 
   |  Document5 | NULL | 
259
Sandeep Jindal

Sur INNER JOINs, ils sont interchangeables et l’optimiseur les réorganisera à volonté.

Sur OUTER JOINs, ils ne sont pas nécessairement interchangeables, selon le côté de la jointure dont ils dépendent.

Je les mets à chaque endroit en fonction de la lisibilité.

140
Cade Roux

La façon dont je le fais est:

  • Mettez toujours les conditions de jointure dans la clause ON si vous utilisez un INNER JOIN. Par conséquent, n’ajoutez aucune condition WHERE à la clause ON, mais insérez-les dans la clause WHERE.

  • Si vous effectuez un LEFT JOIN, ajoutez les conditions WHERE à la clause ON pour la table dans le côté à droite de la jointure. . Ceci est indispensable, car l'ajout d'une clause WHERE faisant référence au côté droit de la jointure convertira la jointure en INNER JOIN.

    L'exception est lorsque vous recherchez les enregistrements qui ne se trouvent pas dans une table particulière. Vous ajouteriez la référence à un identifiant unique (qui n'est pas toujours NULL) dans la table RIGHT JOIN à la clause WHERE de la manière suivante: WHERE t2.idfield IS NULL. Ainsi, la seule fois où vous devriez référencer une table du côté droit de la jointure est de rechercher les enregistrements qui ne sont pas dans la table.

40
HLGEM

Sur une jointure interne, ils signifient la même chose. Cependant, vous obtiendrez des résultats différents dans une jointure externe en fonction de la présence de la condition de jointure dans la clause WHERE vs la clause ON. Jetez un oeil à cette question connexe et cette réponse (par moi).

Je pense qu'il est plus logique de prendre l'habitude de toujours mettre la condition de jointure dans la clause ON (à moins qu'il s'agisse d'une jointure externe et que vous le souhaitiez réellement dans la clause where), car cela sera plus clair pour quiconque lisant votre requête. quelles sont les conditions dans lesquelles les tables sont jointes, et cela aide également à éviter que la clause WHERE ne comprenne des dizaines de lignes.

30
matt b

Cet article explique clairement la différence. Il explique également que "ON join_condition vs WHERE join_condition ou join_alias est null".

La clause WHERE filtre le résultat de la clause FROM avec les JOIN, tandis que la clause ON est utilisée pour produire le résultat de la table entre les tables FROM et JOIN.

  1. Si vous voulez produire un résultat de table qui joint deux tables, vous devriez utiliser la clause ON pour déterminer comment les tables sont jointes. Bien entendu, cela peut également filtrer les lignes de la table d'origine dans le cas d'un INNER JOIN, par exemple.
  2. Si vous souhaitez filtrer le produit de la jonction des deux côtés, vous devez utiliser la clause WHERE.
22
Vlad Mihalcea

Il y a une grande différence entre où clause vs sur la clause , quand il s'agit de rejoindre à gauche.

Voici un exemple:

mysql> desc t1; 
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| fid   | int(11)     | NO   |     | NULL    |       |
| v     | varchar(20) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

Il est fid id de la table t2.

mysql> desc t2;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| v     | varchar(10) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

Requête sur "sur la clause":

mysql> SELECT * FROM `t1` left join t2 on fid = t2.id AND t1.v = 'K' 
    -> ;
+----+-----+---+------+------+
| id | fid | v | id   | v    |
+----+-----+---+------+------+
|  1 |   1 | H | NULL | NULL |
|  2 |   1 | B | NULL | NULL |
|  3 |   2 | H | NULL | NULL |
|  4 |   7 | K | NULL | NULL |
|  5 |   5 | L | NULL | NULL |
+----+-----+---+------+------+
5 rows in set (0.00 sec)

Requête sur "clause":

mysql> SELECT * FROM `t1` left join t2 on fid = t2.id where t1.v = 'K';
+----+-----+---+------+------+
| id | fid | v | id   | v    |
+----+-----+---+------+------+
|  4 |   7 | K | NULL | NULL |
+----+-----+---+------+------+
1 row in set (0.00 sec)

Il est clair que la première requête renvoie un enregistrement de t1 et sa ligne dépendante de t2, le cas échéant, pour la ligne t1.v = 'K'.

La deuxième requête renvoie les lignes de t1, mais uniquement pour t1.v = 'K' sera associé à une ligne.

11
Hrishikesh Mishra

En ce qui concerne l'optimiseur, il ne devrait pas y avoir de différence si vous définissez vos clauses de jointure avec ON ou WHERE.

Cependant, IMHO, je pense qu'il est beaucoup plus clair d'utiliser la clause ON lors de la réalisation de jointures. De cette façon, vous avez une section spécifique de votre requête qui dicte la manière dont la jointure est gérée plutôt que mélangée avec le reste des clauses WHERE.

8
Grant Limberg

pour de meilleures performances, les tables doivent avoir une colonne indexée spéciale à utiliser pour JOINS.

donc, si la colonne sur laquelle vous conditionnez n'est pas l'une de ces colonnes indexées, je suppose qu'il est préférable de la conserver dans WHERE.

de sorte que vous vous connectez à l'aide des colonnes indexées, puis après JOIN, vous exécutez la condition sur la colonne non indexée.

1
yakoub abaya

Essayez-vous de joindre des données ou de filtrer des données?

Pour des raisons de lisibilité, il est préférable d’isoler ces cas d’utilisation respectivement sur ON et WHERE.

  • joindre des données en ON
  • filtrer les données dans WHERE

Il peut devenir très difficile de lire une requête où la condition JOIN et une condition de filtrage existent dans la clause WHERE.

En ce qui concerne les performances, vous ne devriez pas voir de différence, bien que différents types de SQL gèrent parfois la planification des requêtes différemment. Cela vaut donc la peine d'essayer ¯\_(ツ)_/¯ (Soyez conscient de la mise en cache affectant la vitesse de la requête)

De même, comme d'autres l'ont déjà noté, si vous utilisez une jointure externe, vous obtiendrez des résultats différents si vous placez la condition de filtre dans la clause ON car elle affecte uniquement l'une des tables.

J'ai écrit un article plus détaillé à ce sujet ici: https://dataschool.com/learn/difference-between-where-and-on-in-in-sql

1
matthew david

En SQL, les clauses "WHERE" et "ON" sont en quelque sorte des statemants conditionnels, mais la principale différence entre elles est que la clause "Where" est utilisée dans les instructions Select/Update pour spécifier les conditions, alors que la clause "ON" est utilisé dans les jointures, où il vérifie ou vérifie si les enregistrements sont mis en correspondance dans les tables cible et source, avant que les tables ne soient jointes

Par exemple: - 'WHERE'

SELECT * FROM employee WHERE employee_id=101

Par exemple: - 'ON'

Il existe deux tables employee et employee_details, les colonnes correspondantes sont employee_id.

SELECT * FROM employee 
INNER JOIN employee_details 
ON employee.employee_id = employee_details.employee_id

J'espère avoir répondu à votre question. Revenir pour des éclaircissements.

1
Sharon Fernando

Normalement, le filtrage est traité dans la clause WHERE une fois que les deux tables ont déjà été jointes. Il est possible, cependant, que vous souhaitiez filtrer une ou les deux tables avant de les joindre. c'est-à-dire que la clause where s'applique à l'ensemble des résultats alors que la clause on ne s'applique qu'à la jointure en question.

1
sree

Pour une jointure interne, WHERE et ON peuvent être utilisés de manière interchangeable. En fait, il est possible d'utiliser ON dans une sous-requête corrélée. Par exemple:

update mytable
set myscore=100
where exists (
select 1 from table1
inner join table2
on (table2.key = mytable.key)
inner join table3
on (table3.key = table2.key and table3.key = table1.key)
...
)

C'est (IMHO) complètement déroutant pour un humain, et il est très facile d'oublier de lier table1 à quoi que ce soit (car la table "driver" n'a pas de clause "on"), mais c'est légal.

1
Austin Barry

Je pense que c'est l'effet de la séquence de jointure. Dans le cas de jointure en haut à gauche, SQL joint gauche en premier, puis filtre où. Dans le cas de downer, recherchez Orders.ID = 12345 en premier, puis rejoignez.

1
Xing-Wei Lin

Considérons ces tableaux:

UNE

id | SomeData

B

id | id_A | SomeOtherData

id_A étant une clé étrangère de la table A

Écrire cette requête:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A;

Fournira ce résultat:

/ : part of the result
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////+-------+-------------------------+
|/////////////////////////////|
+-----------------------------+

Ce qui est dans A mais pas dans B signifie qu'il existe des valeurs nulles pour B.


Considérons maintenant une partie spécifique dans B.id_A et soulignons-la à partir du résultat précédent:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////+---+///|                         |
|/////////////////////|***|///|                         |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+

Écrire cette requête:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
AND B.id_A = SpecificPart;

Fournira ce résultat:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|       |                         |
|/////////////////////|       |                         |
|/////////////////////+---+   |                         |
|/////////////////////|***|   |                         |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+

Parce que cela supprime dans la jointure interne les valeurs qui ne sont pas dans B.id_A = SpecificPart


Maintenant, changeons la requête en ceci:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
WHERE B.id_A = SpecificPart;

Le résultat est maintenant:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|                     |       |                         |
|                     |       |                         |
|                     +---+   |                         |
|                     |***|   |                         |
|                     +---+---+-------------------------+
|                             |
+-----------------------------+

Parce que tout le résultat est filtré sur B.id_A = SpecificPart en supprimant les parties B.id_A = NULL, qui sont dans le A qui ne sont pas dans B

0
Cid

Je pense que cette distinction peut être mieux expliquée via le ordre logique des opérations en SQL , qui est simplifié:

  • FROM(jointures comprises)
  • WHEREname__
  • GROUP BY
  • Agrégations
  • HAVINGname__
  • WINDOWname__
  • SELECTname__
  • DISTINCTname__
  • UNIONname__, INTERSECTname__, EXCEPTname__
  • ORDER BY
  • OFFSETname__
  • FETCHname__

Les jointures ne sont pas une clause de l'instruction select, mais un opérateur à l'intérieur de FROMname__. Ainsi, toutes les clauses ONappartenant à l'opérateur JOINont "déjà eu lieu" logiquement au moment où le traitement logique atteint la clause WHEREname__. Cela signifie que dans le cas d'un LEFT JOIN, par exemple, la sémantique de la jointure externe est déjà arrivée au moment où la clause WHEREest appliquée.

J'ai expliqué l'exemple suivant plus en détail dans cet article de blog . Lors de l'exécution de cette requête:

SELECT a.actor_id, a.first_name, a.last_name, count(fa.film_id)
FROM actor a
LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id
WHERE film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;

Le LEFT JOIN n'a pas vraiment d'effet utile, car même si un acteur ne joue pas dans un film, l'acteur sera filtré, car son FILM_ID sera NULLet la clause WHEREfiltrera une telle ligne. Le résultat est quelque chose comme:

ACTOR_ID  FIRST_NAME  LAST_NAME  COUNT
--------------------------------------
194       MERYL       ALLEN      1
198       MARY        KEITEL     1
30        SANDRA      PECK       1
85        MINNIE      ZELLWEGER  1
123       JULIANNE    DENCH      1

C'est à dire. tout comme si nous avions rejoint les deux tables. Si nous déplaçons le prédicat de filtre dans la clause ONname__, il devient désormais un critère pour la jointure externe:

SELECT a.actor_id, a.first_name, a.last_name, count(fa.film_id)
FROM actor a
LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id
  AND film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;

Cela signifie que le résultat contiendra des acteurs sans aucun film ou sans film avec FILM_ID < 10

ACTOR_ID  FIRST_NAME  LAST_NAME     COUNT
-----------------------------------------
3         ED          CHASE         0
4         JENNIFER    DAVIS         0
5         JOHNNY      LOLLOBRIGIDA  0
6         BETTE       NICHOLSON     0
...
1         PENELOPE    GUINESS       1
200       THORA       TEMPLE        1
2         NICK        WAHLBERG      1
198       MARY        KEITEL        1

En bref

Placez toujours votre prédicat là où cela a le plus de sens, logiquement.

0
Lukas Eder