Clause SQL JOIN - clause WHERE ou clause ON

690

Après l'avoir lu, il ne s'agit pas d' un doublon de jointures SQL explicites et implicites . La réponse peut être liée (ou même la même) 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.

BCS
la source
2
Juste pour les futurs lecteurs et vos informations, vous devriez lire l'ordre d'exécution sql. Cela vous aiderait plus précisément à comprendre la différence sous-jacente.
Rahul Neekhra

Réponses:

871

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 retournera une commande et ses lignes, le cas échéant, pour le numéro de commande 12345. Le second retournera toutes les commandes, mais seulement la commande12345 aura des lignes associées.

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

Joel Coehoorn
la source
83
obtiendrez-vous de meilleures performances en plaçant la clause where dans la clause "on" pour une jointure interne?
FistOfFury
96
@FistOfFury Sql Server utilise une procédure d'optimisation de requête qui compile et évalue votre code pour produire le meilleur plan d'exécution possible. Ce n'est pas parfait, mais la plupart du temps, cela n'aura pas d'importance et vous obtiendrez le même plan d'exécution dans les deux cas.
Joel Coehoorn
18
Dans Postgres, j'ai remarqué qu'ils n'étaient PAS équivalents et entraînaient des plans de requête différents. Si vous utilisez ON, cela a entraîné l'utilisation de matérialiser. Si vous avez utilisé OERE, il a utilisé un hachage. Le matérialiser avait un cas pire qui était 10 fois plus cher que le hachage. Cela utilisait un ensemble d'ID plutôt qu'un seul ID.
JamesHutchison
13
@JamesHutchison Il est difficile de faire des généralisations de performances fiables basées sur des comportements observés comme celui-ci. Ce qui était vrai un jour a tendance à se tromper le lendemain, car il s'agit d'un détail d'implémentation plutôt que d'un comportement documenté. Les équipes de base de données recherchent toujours des emplacements pour améliorer les performances de l'optimiseur. Je serai surpris si le comportement ON ne s'améliore pas pour correspondre au WHERE. Il peut même ne pas apparaître nulle part dans les notes de version d'une version à une autre que quelque chose comme "des améliorations générales des performances.
Joel Coehoorn
4
@FiHoran Ce n'est pas ainsi que fonctionne Sql Server. Il pré-filtrera agressivement en fonction des éléments de la clause WHERE lorsque les statistiques montrent que cela peut être utile.
Joel Coehoorn
364
  • Peu importe pour les jointures internes
  • Questions pour les jointures externes

    une. WHEREclause: Après adhésion. Les enregistrements seront filtrés une fois la jointure effectuée.

    b. ONclause - Avant d' adhérer. Les enregistrements (du tableau de droite) seront filtrés avant de rejoindre. Cela peut finir comme nul dans le résultat (depuis la jointure EXTERNE).



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) WHEREClause intérieure :

  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) JOINClause intérieure

  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 | 
Sandeep Jindal
la source
40
OMI, c'est la meilleure réponse car elle montre clairement ce qui se passe «sous le capot» des autres réponses populaires.
psrpsrpsr
1
Excellente explication .... bravo! - Juste curieux, qu'as-tu fait pour obtenir ça intermediate join table? Une commande «Expliquer»?
Manuel Jordan
1
@ManuelJordan Non, c'est juste pour une explication. Une base de données peut faire quelque chose de plus performant que de créer une table intermédiaire.
Sandeep Jindal
Compris, j'ai supposé qu'un troisième outil avait peut-être été utilisé.
Manuel Jordan
146

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 aux deux endroits en fonction de la lisibilité.

Cade Roux
la source
C'est probablement beaucoup plus clair dans la clause Where, en particulier dans les expressions lambda Linq-To-EntitiesOrders.Join( OrderLines, x => x.ID, x => OrderID, (o,l) => new {Orders = o, Lines = l}).Where( ol => ol.Orders.ID = 12345)
Triynko
49

Ma façon de procéder est:

  • Mettez toujours les conditions de jointure dans la ONclause si vous faites un INNER JOIN. Donc, n'ajoutez aucune condition WHERE à la clause ON, mettez-les dans la WHEREclause.

  • Si vous effectuez une LEFT JOIN, ajoutez des conditions WHERE à la ONclause de la table dans le côté droit de la jointure. C'est un must, car l'ajout d'une clause WHERE qui fait 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 ajoutez la référence à un identifiant unique (ce n'est pas toujours NULL) dans la droite table de jointure à la clause WHERE de cette façon: WHERE t2.idfield IS NULL. Ainsi, la seule fois où vous devez référencer une table sur le côté droit de la jointure est de rechercher les enregistrements qui ne figurent pas dans la table.

HLGEM
la source
8
C'est la meilleure réponse que j'ai lue jusqu'ici. Cela a du sens une fois que votre cerveau comprend qu'une jointure gauche va renvoyer toutes les lignes du tableau de gauche et que vous devez la filtrer plus tard.
Nick Larsen
si vous joignez une table externe avec une colonne nullable, vous pouvez toujours "où" cette colonne étant nulle sans en faire une jointure interne? Ce n'est pas exactement la recherche des enregistrements qui ne se trouvent pas uniquement dans une table particulière. Vous pouvez rechercher 1. n'existe pas 2. n'a pas de valeur du tout.
Près du
Je veux dire que vous pouvez rechercher les deux: "1. pas existé 2. n'a pas de valeur du tout" ensemble. Et cela s'applique au cas où ce champ n'est pas idfield.
Près du
Comme je l'ai rencontré ce cas: la recherche de participants, y compris les étudiants de première année (données non encore entrées) sans contact d'urgence.
Près du
30

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

Je pense que cela a le plus de sens d'avoir l'habitude de toujours mettre la condition de jointure dans la clause ON (à moins qu'il ne s'agisse d'une jointure externe et que vous ne la vouliez réellement dans la clause where) car cela le rend plus clair pour quiconque lit votre requête les conditions dans lesquelles les tables sont jointes, et cela permet également d'éviter que la clause WHERE ne soit longue de plusieurs dizaines de lignes.

mat b
la source
26

C'est une question très courante, donc cette réponse est basée sur cet article que j'ai écrit.

Relation de table

Considérant que nous avons les tableaux postet post_commenttableaux suivants:

Les tables <code> post </code> et <code> post_comment </code>

Le posta les enregistrements suivants:

| id | title     |
|----|-----------|
| 1  | Java      |
| 2  | Hibernate |
| 3  | JPA       |

et post_commenta les trois lignes suivantes:

| id | review    | post_id |
|----|-----------|---------|
| 1  | Good      | 1       |
| 2  | Excellent | 1       |
| 3  | Awesome   | 2       |

SQL INNER JOIN

La clause SQL JOIN vous permet d'associer des lignes appartenant à différentes tables. Par exemple, un CROSS JOIN créera un produit cartésien contenant toutes les combinaisons possibles de lignes entre les deux tables de jonction.

Bien que CROSS JOIN soit utile dans certains scénarios, la plupart du temps, vous souhaitez joindre des tables en fonction d'une condition spécifique. Et c'est là que INNER JOIN entre en jeu.

Le SQL INNER JOIN nous permet de filtrer le produit cartésien de joindre deux tables en fonction d'une condition qui est spécifiée via la clause ON.

SQL INNER JOIN - ON condition "toujours vrai"

Si vous fournissez une condition "toujours vrai", l'INNER JOIN ne filtrera pas les enregistrements joints et le jeu de résultats contiendra le produit cartésien des deux tables de jointure.

Par exemple, si nous exécutons la requête SQL INNER JOIN suivante:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 1

Nous obtiendrons toutes les combinaisons postet post_commentenregistrements:

| p.id    | pc.id      |
|---------|------------|
| 1       | 1          |
| 1       | 2          |
| 1       | 3          |
| 2       | 1          |
| 2       | 2          |
| 2       | 3          |
| 3       | 1          |
| 3       | 2          |
| 3       | 3          |

Donc, si la condition de la clause ON est "toujours vraie", l'INNER JOIN est simplement équivalent à une requête CROSS JOIN:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 1
ORDER BY p.id, pc.id

SQL INNER JOIN - ON "toujours faux" condition

D'un autre côté, si la condition de la clause ON est "toujours fausse", alors tous les enregistrements joints vont être filtrés et le jeu de résultats sera vide.

Donc, si nous exécutons la requête SQL INNER JOIN suivante:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 0
ORDER BY p.id, pc.id

Nous n'obtiendrons aucun résultat:

| p.id    | pc.id      |
|---------|------------|

En effet, la requête ci-dessus est équivalente à la requête CROSS JOIN suivante:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 0
ORDER BY p.id, pc.id

Clause SQL INNER JOIN - ON utilisant les colonnes Clé étrangère et Clé primaire

La condition de clause ON la plus courante est celle qui fait correspondre la colonne Clé étrangère de la table enfant à la colonne Clé primaire de la table parent, comme illustré par la requête suivante:

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p
INNER JOIN post_comment pc ON pc.post_id = p.id
ORDER BY p.id, pc.id

Lors de l'exécution de la requête SQL INNER JOIN ci-dessus, nous obtenons le jeu de résultats suivant:

| p.id    | pc.post_id | pc.id      | p.title    | pc.review |
|---------|------------|------------|------------|-----------|
| 1       | 1          | 1          | Java       | Good      |
| 1       | 1          | 2          | Java       | Excellent |
| 2       | 2          | 3          | Hibernate  | Awesome   |

Ainsi, seuls les enregistrements qui correspondent à la condition de la clause ON sont inclus dans le jeu de résultats de la requête. Dans notre cas, le jeu de résultats contient tout le postlong avec leurs post_commentenregistrements. Les postlignes qui n'ont aucun associé post_commentsont exclues car elles ne peuvent pas satisfaire à la condition de clause ON.

Encore une fois, la requête SQL INNER JOIN ci-dessus est équivalente à la requête CROSS JOIN suivante:

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p, post_comment pc
WHERE pc.post_id = p.id

Les lignes non frappées sont celles qui satisfont la clause WHERE, et seuls ces enregistrements vont être inclus dans le jeu de résultats. C'est le meilleur moyen de visualiser le fonctionnement de la clause INNER JOIN.

| p.id | pc.post_id | pc.id | p.title | pc.review |
| ------ | ------------ | ------- | ----------- | --------- - |
| 1 | 1 | 1 | Java | Bon |
| 1 | 1 | 2 | Java | Excellent |
| 1 | 2 | 3 | Java | Génial | 
| 2 | 1 | 1 | Hibernate | Bon | 
| 2 | 1 | 2 | Hibernate | Excellent |
| 2 | 2 | 3 | Hibernate | Génial |
| 3 | 1 | 1 | JPA | Bon | 
| 3 | 1 | 2 | JPA | Excellent | 
| 3 | 2 | 3 | JPA | Génial |

Conclusion

Une instruction INNER JOIN peut être réécrite en tant que CROSS JOIN avec une clause WHERE correspondant à la même condition que vous avez utilisée dans la clause ON de la requête INNER JOIN.

Cela ne s'applique pas uniquement à INNER JOIN, pas à OUTER JOIN.

Vlad Mihalcea
la source
11

Il y a une grande différence entre la clause where par rapport à l' article , quand il vient à se joindre à 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 y a 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 "on 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 where":

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 des lignes de t1, mais uniquement pour t1.v = 'K' aura une ligne associée.

Hrishikesh Mishra
la source
9

En termes d'optimiseur, cela ne devrait pas faire de différence si vous définissez vos clauses de jointure avec ON ou WHERE.

Cependant, à mon humble avis, je pense qu'il est beaucoup plus clair d'utiliser la clause ON lors de l'exécution de jointures. De cette façon, vous avez une section spécifique de votre requête qui dicte la façon dont la jointure est gérée par rapport au mélange des autres clauses WHERE.

Grant Limberg
la source
7

Prenons ces tableaux:

UNE

id | SomeData

B

id | id_A | SomeOtherData

id_A être une clé étrangère à la table A

Écriture de 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 en A mais pas en B signifie qu'il y a des valeurs nulles pour B.


Maintenant, considérons une partie spécifique de B.id_A, et mettons-la en évidence à partir du résultat précédent:

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

Écriture de 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é contre la B.id_A = SpecificPartsuppression des parties B.id_A = NULL, qui sont dans le A qui ne sont pas dans le B

Cid
la source
4

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

Pour plus de lisibilité, il est plus judicieux d'isoler ces cas d'utilisation respectivement sur ON et WHERE.

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

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

En termes de 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, il peut donc être utile d'essayer ¯\_(ツ)_/¯ (soyez conscient que la mise en cache affecte la vitesse de requête)

Comme d'autres l'ont également remarqué, 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 n'affecte qu'une des tables.

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

Matthew David
la source
2

En SQL, les clauses 'WHERE' et 'ON' sont des sortes de 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, tandis 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: - 'OERE'

SELECT * FROM employee WHERE employee_id=101

Par exemple: - 'ON'

Il y a 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. Revenez pour toute clarification.

Sharon Fernando
la source
Mais vous pourriez utiliser un mot clé WHEREà la place de ON, n'est-ce pas? sqlfiddle.com/#!2/ae5b0/14/0
Qwerty
1

Je pense que c'est l'effet de séquence de jointure. Dans le cas de jointure supérieur gauche, SQL fait d'abord la jointure gauche, puis fait où le filtre. Dans le cas inférieur, recherchez d'abord Orders.ID = 12345, puis joignez-vous.

Xing-Wei Lin
la source
1

Pour une jointure intérieure, WHEREet ONpeut être utilisé de manière interchangeable. En fait, il est possible de l'utiliser ONdans 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 (à mon humble avis) 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.

Austin Barry
la source
1

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 ne fait pas partie de ces colonnes indexées, je soupçonne qu'il vaut mieux la conserver dans WHERE.

vous vous JOIGNEZ donc en utilisant les colonnes indexées, puis après JOIN vous exécutez la condition sur la colonne non indexée.

abaya yakoub
la source
1

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

sree
la source
Ce n'est tout simplement pas le cas puisque les SGBD sont "normalement" optimisés.
philipxy
1

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

  • FROM (y compris les jointures)
  • WHERE
  • GROUP BY
  • Agrégations
  • HAVING
  • WINDOW
  • SELECT
  • DISTINCT
  • UNION, INTERSECT,EXCEPT
  • ORDER BY
  • OFFSET
  • FETCH

Les jointures ne sont pas une clause de l'instruction select, mais un opérateur à l'intérieur de FROM. Ainsi, toutes les ONclauses appartenant à l' JOINopérateur correspondant se sont "déjà produites" logiquement au moment où le traitement logique atteint la WHEREclause. Cela signifie que dans le cas d'un LEFT JOIN, par exemple, la sémantique de la jointure externe s'est déjà produite au moment où leWHERE clause est 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;

Cela LEFT JOINn'a pas vraiment d'effet utile, car même si un acteur n'a pas joué dans un film, l'acteur sera filtré comme il le FILM_IDsera NULLet la WHEREclause filtrera 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 comme si nous rejoignions intérieurement les deux tables. Si nous déplaçons le prédicat de filtre dans la ONclause, il devient maintenant 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 aucun 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

Mettez toujours votre prédicat là où il est le plus logique, logiquement.

Lukas Eder
la source
0

Concernant votre question,

Il en est de même à la fois sur ou sur une jointure interne tant que votre serveur peut l'obtenir:

select * from a inner join b on a.c = b.c

et

select * from a inner join b where a.c = b.c

L'option «où» que tous les interprètes ne connaissent pas doit donc être évitée. Et bien sûr, la clause «on» est plus claire.

Ezequiel
la source
-5

c'est ma solution.

SELECT song_ID,songs.fullname, singers.fullname
FROM music JOIN songs ON songs.ID = music.song_ID  
JOIN singers ON singers.ID = music.singer_ID
GROUP BY songs.fullname

Vous devez avoir le GROUP BYpour le faire fonctionner.

J'espère que cette aide.

Le Quang Chien
la source
10
Le regroupement sur seulement songs.fullname pendant que vous sélectionnez également song_id et singers.fullname va être un problème dans la plupart des bases de données.
btilly