SQL JOIN - WHERE-Klausel vs. ON-Klausel


685

Nach dem Lesen handelt es sich nicht um ein Duplikat von Explicit vs Implicit SQL Joins . Die Antwort kann verwandt (oder sogar gleich) sein, aber die Frage ist anders.


Was ist der Unterschied und was sollte in jedem gehen?

Wenn ich die Theorie richtig verstehe, sollte das Abfrageoptimierungsprogramm beide austauschbar verwenden können.


2
Nur für zukünftige Leser und Ihre Informationen sollten Sie die Reihenfolge der SQL-Ausführung lesen. Dies würde Ihnen helfen, den zugrunde liegenden Unterschied genauer zu verstehen.
Rahul Neekhra

Antworten:


869

Sie sind nicht dasselbe.

Betrachten Sie diese Fragen:

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

und

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

Der erste gibt eine Bestellung und gegebenenfalls deren Zeilen für die Bestellnummer zurück 12345. Die zweite Option gibt alle Bestellungen zurück, aber nur der Bestellung 12345sind Zeilen zugeordnet.

Mit einem INNER JOINsind die Klauseln effektiv gleichwertig. Nur weil sie funktional gleich sind, weil sie die gleichen Ergebnisse liefern, heißt das nicht, dass die beiden Arten von Klauseln die gleiche semantische Bedeutung haben.


83
Werden Sie eine bessere Leistung erzielen, wenn Sie die where-Klausel in die "on" -Klausel für einen inneren Join einfügen?
FistOfFury

96
@FistOfFury SQL Server verwendet eine Abfrageoptimierungsprozedur, die Ihren Code kompiliert und auswertet, um den bestmöglichen Ausführungsplan zu erstellen. Es ist nicht perfekt, aber meistens spielt es keine Rolle und Sie erhalten in beiden Fällen den gleichen Ausführungsplan.
Joel Coehoorn

18
In Postgres habe ich festgestellt, dass sie NICHT gleichwertig sind und zu unterschiedlichen Abfrageplänen führen. Wenn Sie ON verwenden, wird materialise verwendet. Wenn Sie WHERE verwendet haben, wurde ein Hash verwendet. Das Materialisieren hatte einen schlimmeren Fall, der 10x teurer war als der Hash. Hierbei wurde eine Reihe von IDs anstelle einer einzelnen ID verwendet.
James Hutchison

13
@JamesHutchison Es ist schwierig, zuverlässige Leistungsverallgemeinerungen basierend auf beobachteten Verhaltensweisen wie diesem vorzunehmen. Was an einem Tag wahr war, ist am nächsten eher falsch, da dies eher ein Implementierungsdetail als ein dokumentiertes Verhalten ist. Datenbankteams suchen immer nach Orten, um die Leistung des Optimierers zu verbessern. Ich bin überrascht, wenn sich das EIN-Verhalten nicht an das WO anpasst. Es wird möglicherweise nicht einmal irgendwo in Versionshinweisen von Version zu Version angezeigt, außer so etwas wie "allgemeine Leistungsverbesserungen".
Joel Coehoorn

4
@FiHoran So funktioniert SQL Server nicht. Es wird aggressiv basierend auf Elementen aus der WHERE-Klausel vorgefiltert, wenn Statistiken zeigen, dass dies hilfreich sein kann.
Joel Coehoorn

362
  • Ist für innere Verbindungen nicht wichtig
  • Angelegenheiten für äußere Verbindungen

    ein. WHEREKlausel: Nachher Beitritt. Datensätze werden nach dem Beitritt gefiltert.

    b. ONKlausel - Vor dem Beitritt. Datensätze (aus der rechten Tabelle) werden vor dem Beitritt gefiltert. Dies kann im Ergebnis als null enden (seit OUTER-Join).



Beispiel : Betrachten Sie die folgenden Tabellen:

    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) Inside- WHEREKlausel:

  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) Inside- JOINKlausel

  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 | 

40
IMO ist dies die beste Antwort, da sie deutlich zeigt, was unter der Haube der anderen populären Antworten vor sich geht.
psrpsrpsr

1
Hervorragende Erklärung ... gut gemacht! - Nur neugierig, was hast du getan, um das zu bekommen intermediate join table? Ein 'Erklären'-Befehl?
Manuel Jordan

1
@ ManuelJordan Nein, das ist nur zur Erklärung. Eine Datenbank kann etwas Performanteres tun, als eine Zwischentabelle zu erstellen.
Sandeep Jindal

Verstanden nahm ich an, dass vielleicht ein drittes Werkzeug verwendet wurde.
Manuel Jordan

145

Auf INNER JOIN s sind sie austauschbar, und der Optimierer ordnet sie nach Belieben neu an.

Auf OUTER JOIN s sind sie nicht unbedingt austauschbar, abhängig davon, von welcher Seite der Verknüpfung sie abhängen.

Ich habe sie je nach Lesbarkeit an beiden Stellen platziert.



Es ist wahrscheinlich viel klarer in der Where-Klausel, insbesondere in Linq-To-Entities-Lambda-AusdrückenOrders.Join( OrderLines, x => x.ID, x => OrderID, (o,l) => new {Orders = o, Lines = l}).Where( ol => ol.Orders.ID = 12345)
Triynko

49

Ich mache es so:

  • Fügen Sie die Join-Bedingungen immer in die ONKlausel ein, wenn Sie eine INNER JOIN. Fügen Sie der ON-Klausel also keine WHERE-Bedingungen hinzu, sondern fügen Sie sie in die WHEREKlausel ein.

  • Wenn Sie a ausführen LEFT JOIN, fügen Sie der ONKlausel für die Tabelle rechts alle WHERE-Bedingungen hinzu Seite des Joins . Dies ist ein Muss, da durch Hinzufügen einer WHERE-Klausel, die auf die rechte Seite des Joins verweist, der Join in einen INNER JOIN konvertiert wird.

    Die Ausnahme ist, wenn Sie nach Datensätzen suchen, die sich nicht in einer bestimmten Tabelle befinden. Sie würden den Verweis auf einen eindeutigen Bezeichner (der niemals NULL ist) in der Tabelle RIGHT JOIN zur WHERE-Klausel auf folgende Weise hinzufügen : WHERE t2.idfield IS NULL. Sie sollten also nur auf eine Tabelle auf der rechten Seite des Joins verweisen, um die Datensätze zu finden, die nicht in der Tabelle enthalten sind.


8
Dies ist die beste Antwort, die ich bisher gelesen habe. Völlig macht Sinn , wenn Ihr Gehirn eine linke versteht join wird gehen alle Zeilen in der linken Tabelle zurück , und Sie müssen es filtern später.
Nick Larsen

Wenn Sie eine Tabelle mit einer nullbaren Spalte äußerlich verknüpfen, können Sie dann immer noch "wo" diese Spalte null sein, ohne sie zu einer inneren Verknüpfung zu machen? Dabei wird nicht genau nach Datensätzen gesucht, die sich nicht nur in einer bestimmten Tabelle befinden. Sie können suchen nach 1. nicht vorhanden 2. hat überhaupt keinen Wert.
In der Nähe des

Ich meine, Sie können nach beiden suchen: "1. existierte nicht 2. hat überhaupt keinen Wert" zusammen. Dies gilt für den Fall, dass dieses Feld kein ID-Feld ist.
In der Nähe des

Als ich auf diesen Fall stieß: Suche nach Teilnehmern einschließlich Neuling (Daten noch nicht eingegeben) ohne Notfallkontakt.
In der Nähe des

30

Bei einer inneren Verbindung bedeuten sie dasselbe. Je nachdem, ob Sie die Join-Bedingung in die WHERE-Klausel oder die ON-Klausel einfügen, erhalten Sie jedoch unterschiedliche Ergebnisse in einem Outer-Join. Schauen Sie sich diese verwandte Frage und diese Antwort (von mir) an.

Ich denke, es ist am sinnvollsten, die Join-Bedingung immer in die ON-Klausel aufzunehmen (es sei denn, es handelt sich um eine äußere Verknüpfung, und Sie möchten sie tatsächlich in der where-Klausel haben), da dies für jeden, der Ihre Abfrage liest, klarer wird Unter welchen Bedingungen werden die Tabellen verknüpft, und es wird auch verhindert, dass die WHERE-Klausel Dutzende von Zeilen lang ist.


26

Dies ist eine sehr häufige Frage, daher basiert diese Antwort auf diesem Artikel, den ich geschrieben habe.

Tabellenbeziehung

In Anbetracht dessen haben wir Folgendes postund post_commentTabellen:

Die Tabellen <code> post </ code> und <code> post_comment </ code>

Das posthat folgende Aufzeichnungen:

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

und das post_commenthat die folgenden drei Zeilen:

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

SQL INNER JOIN

Mit der SQL JOIN-Klausel können Sie Zeilen zuordnen, die zu verschiedenen Tabellen gehören. Ein CROSS JOIN erstellt beispielsweise ein kartesisches Produkt, das alle möglichen Kombinationen von Zeilen zwischen den beiden Verknüpfungstabellen enthält.

Während CROSS JOIN in bestimmten Szenarien nützlich ist, möchten Sie meistens Tabellen basierend auf einer bestimmten Bedingung verknüpfen. Und hier kommt INNER JOIN ins Spiel.

Mit SQL INNER JOIN können wir das kartesische Produkt des Verbindens zweier Tabellen basierend auf einer Bedingung filtern, die über die ON-Klausel angegeben wird.

SQL INNER JOIN - ON "immer wahr" Bedingung

Wenn Sie eine "immer wahre" Bedingung angeben, filtert INNER JOIN die verknüpften Datensätze nicht und die Ergebnismenge enthält das kartesische Produkt der beiden Verknüpfungstabellen.

Zum Beispiel, wenn wir die folgende SQL INNER JOIN-Abfrage ausführen:

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

Wir erhalten alle Kombinationen postund post_commentAufzeichnungen:

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

Wenn die Bedingung der ON-Klausel "immer wahr" ist, entspricht INNER JOIN einfach einer CROSS JOIN-Abfrage:

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 "immer falsch" Bedingung

Wenn andererseits die ON-Klauselbedingung "immer falsch" ist, werden alle verknüpften Datensätze herausgefiltert und die Ergebnismenge ist leer.

Wenn wir also die folgende SQL INNER JOIN-Abfrage ausführen:

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

Wir werden kein Ergebnis zurückbekommen:

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

Dies liegt daran, dass die obige Abfrage der folgenden CROSS JOIN-Abfrage entspricht:

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

SQL INNER JOIN - ON-Klausel unter Verwendung der Spalten Fremdschlüssel und Primärschlüssel

Die häufigste ON-Klauselbedingung ist diejenige, die die Fremdschlüsselspalte in der untergeordneten Tabelle mit der Primärschlüsselspalte in der übergeordneten Tabelle übereinstimmt, wie in der folgenden Abfrage dargestellt:

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

Bei der Ausführung der obigen SQL INNER JOIN-Abfrage erhalten wir die folgende Ergebnismenge:

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

Daher werden nur die Datensätze, die der ON-Klauselbedingung entsprechen, in die Abfrageergebnismenge aufgenommen. In unserem Fall enthält die Ergebnismenge alle postzusammen mit ihren post_commentDatensätzen. Die nicht zugeordneten postZeilen post_commentwerden ausgeschlossen, da sie die ON-Klauselbedingung nicht erfüllen können.

Auch hier entspricht die obige SQL INNER JOIN-Abfrage der folgenden CROSS JOIN-Abfrage:

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

Die nicht angeschlagenen Zeilen erfüllen die WHERE-Klausel, und nur diese Datensätze werden in die Ergebnismenge aufgenommen. Auf diese Weise können Sie am besten visualisieren, wie die INNER JOIN-Klausel funktioniert.

| p.id | pc.post_id | pc.id | p.title | pc.review |
| ------ | ------------ | ------- | ----------- | --------- - |
| 1 | 1 | 1 | Java | Gut |
| 1 | 1 | 2 | Java | Ausgezeichnet |
| 1 | 2 | 3 | Java | Genial | 
| 2 | 1 | 1 | Ruhezustand | Gut | 
| 2 | 1 | 2 | Ruhezustand | Ausgezeichnet |
| 2 | 2 | 3 | Ruhezustand | Genial |
| 3 | 1 | 1 | JPA | Gut | 
| 3 | 1 | 2 | JPA | Ausgezeichnet | 
| 3 | 2 | 3 | JPA | Genial |

Fazit

Eine INNER JOIN-Anweisung kann als CROSS JOIN mit einer WHERE-Klausel umgeschrieben werden, die der gleichen Bedingung entspricht, die Sie in der ON-Klausel der INNER JOIN-Abfrage verwendet haben.

Nicht, dass dies nur für INNER JOIN gilt, nicht für OUTER JOIN.


11

Es gibt einen großen Unterschied zwischen der where-Klausel und der on-Klausel , wenn es um Left Join geht.

Hier ist ein Beispiel:

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

Dort ist fid die ID von Tabelle 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)

Abfrage zu "on-Klausel":

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)

Abfrage zu "where-Klausel":

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)

Es ist klar, dass die erste Abfrage einen Datensatz von t1 und seine abhängige Zeile von t2, falls vorhanden, für Zeile t1.v = 'K' zurückgibt.

Die zweite Abfrage gibt Zeilen von t1 zurück, aber nur für t1.v = 'K' ist eine Zeile zugeordnet.


9

In Bezug auf das Optimierungsprogramm sollte es keinen Unterschied machen, ob Sie Ihre Join-Klauseln mit ON oder WHERE definieren.

Ich denke jedoch, es ist viel klarer, die ON-Klausel zu verwenden, wenn Joins ausgeführt werden. Auf diese Weise haben Sie einen bestimmten Abschnitt Ihrer Abfrage, der vorschreibt, wie der Join behandelt wird, anstatt ihn mit den übrigen WHERE-Klauseln zu vermischen.


7

Betrachten wir diese Tabellen:

EIN

id | SomeData

B.

id | id_A | SomeOtherData

id_A ein Fremdschlüssel zu Tisch sein A

Schreiben dieser Abfrage:

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

Wird dieses Ergebnis liefern:

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

Was in A, aber nicht in B ist, bedeutet, dass es für B Nullwerte gibt.


Betrachten wir nun einen bestimmten Teil in B.id_Aund heben Sie ihn aus dem vorherigen Ergebnis hervor:

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

Schreiben dieser Abfrage:

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

Wird dieses Ergebnis liefern:

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

Weil dies im inneren Join die Werte entfernt, die nicht in sind B.id_A = SpecificPart


Ändern wir nun die Abfrage wie folgt:

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

Das Ergebnis ist jetzt:

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

Da das gesamte Ergebnis gegen das B.id_A = SpecificPartEntfernen der Teile gefiltert wird B.id_A = NULL, die sich in A befinden und nicht in B.


4

Versuchen Sie, Daten zu verbinden oder Daten zu filtern?

Aus Gründen der Lesbarkeit ist es am sinnvollsten, diese Anwendungsfälle auf ON bzw. WHERE zu isolieren.

  • Daten in ON verbinden
  • Daten in WHERE filtern

Es kann sehr schwierig werden, eine Abfrage zu lesen, bei der die JOIN-Bedingung und eine Filterbedingung in der WHERE-Klausel vorhanden sind.

In Bezug auf die Leistung sollten Sie keinen Unterschied feststellen, obwohl verschiedene SQL-Typen die Abfrageplanung manchmal unterschiedlich handhaben, sodass es sich lohnen kann, sie auszuprobieren ¯\_(ツ)_/¯( beachten Sie, dass das Caching die Abfragegeschwindigkeit beeinflusst).

Wie andere bereits bemerkt haben, erhalten Sie bei Verwendung eines äußeren Joins unterschiedliche Ergebnisse, wenn Sie die Filterbedingung in die ON-Klausel einfügen, da sie nur eine der Tabellen betrifft.

Ich habe hier einen ausführlicheren Beitrag dazu geschrieben: https://dataschool.com/learn/difference-between-where-and-on-in-sql


2

In SQL sind die Klauseln 'WHERE' und 'ON' bedingte Statemants. Der Hauptunterschied zwischen ihnen besteht jedoch darin, dass die Klausel 'Where' in Select / Update-Anweisungen zum Angeben der Bedingungen verwendet wird, während die Klausel 'ON' verwendet wird wird in Verknüpfungen verwendet, wo überprüft oder überprüft wird, ob die Datensätze in den Ziel- und Quelltabellen übereinstimmen, bevor die Tabellen verknüpft werden

Zum Beispiel: - 'WO'

SELECT * FROM employee WHERE employee_id=101

Zum Beispiel: - 'ON'

Es gibt zwei Tabellen employee und employee_details, die übereinstimmenden Spalten sind employee_id.

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

Hoffe ich habe deine Frage beantwortet. Für Klarstellungen zurücksetzen.


Aber Sie könnten das Schlüsselwort WHEREanstelle von verwenden ON, nicht wahr? sqlfiddle.com/#!2/ae5b0/14/0
Qwerty

1

Ich denke, es ist der Join-Sequenz-Effekt. Im Fall der Verknüpfung oben links führt SQL zuerst die Verknüpfung nach links und dann den Filter where where aus. Suchen Sie im Downer-Fall zuerst Orders.ID = 12345 und schließen Sie sich dann an.


1

Für eine innere Verbindung WHEREund ONkann austauschbar verwendet werden. Tatsächlich ist es möglich, ONin einer korrelierten Unterabfrage zu verwenden. Zum Beispiel:

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

Dies ist (IMHO) für einen Menschen äußerst verwirrend und es ist sehr leicht zu vergessen, table1auf irgendetwas zu verlinken (da die "Treiber" -Tabelle keine "Ein" -Klausel enthält), aber es ist legal.


1

Für eine bessere Leistung sollten Tabellen eine spezielle indizierte Spalte haben, die für JOINS verwendet werden kann.

Wenn also die Spalte, für die Sie eine Bedingung festlegen, keine dieser indizierten Spalten ist, ist es meiner Meinung nach besser, sie in WHERE zu belassen.

Sie verbinden sich also mit den indizierten Spalten und führen nach JOIN die Bedingung für die nicht indizierte Spalte aus.


1

Normalerweise wird die Filterung in der WHERE-Klausel verarbeitet, sobald die beiden Tabellen bereits verbunden wurden. Es ist jedoch möglich, dass Sie eine oder beide Tabellen filtern möchten, bevor Sie sie verbinden. Das heißt, die where-Klausel gilt für die gesamte Ergebnismenge, während die on-Klausel nur für den betreffenden Join gilt.


Dies ist einfach nicht der Fall, da DBMS "normal" optimiert werden.
philipxy

1

Ich denke, diese Unterscheidung kann am besten durch die logische Reihenfolge der Operationen in SQL erklärt werden , die vereinfacht ist:

  • FROM (einschließlich Joins)
  • WHERE
  • GROUP BY
  • Aggregationen
  • HAVING
  • WINDOW
  • SELECT
  • DISTINCT
  • UNION, INTERSECT,EXCEPT
  • ORDER BY
  • OFFSET
  • FETCH

Joins sind keine Klausel der select-Anweisung, sondern ein Operator innerhalb von FROM. Als solche sind alle ONKlauseln, die zum entsprechenden JOINOperator gehören, logisch "bereits passiert" , wenn die logische Verarbeitung die WHEREKlausel erreicht. Dies bedeutet, dass im Fall von LEFT JOINbeispielsweise die Semantik des äußeren Joins bereits zum Zeitpunkt desWHERE Anwendung Klausel ist.

Ich habe das folgende Beispiel in diesem Blog-Beitrag ausführlicher erläutert . Beim Ausführen dieser Abfrage:

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;

Das LEFT JOINhat keinen wirklich nützlichen Effekt, denn selbst wenn ein Schauspieler nicht in einem Film gespielt hat, wird der Schauspieler so gefiltert, wie es sein FILM_IDwird, NULLund die WHEREKlausel filtert eine solche Zeile. Das Ergebnis ist so etwas wie:

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

Das heißt, als ob wir uns innerlich den beiden Tischen angeschlossen hätten. Wenn wir das Filterprädikat in der ONKlausel verschieben, wird es jetzt zu einem Kriterium für die äußere Verknüpfung:

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;

Das heißt, das Ergebnis enthält Schauspieler ohne Filme oder ohne Filme mit 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

Zusamenfassend

Platzieren Sie Ihr Prädikat logischerweise immer dort, wo es am sinnvollsten ist.


0

Was Ihre Frage betrifft,

Es ist dasselbe 'on' oder 'where' bei einem inneren Join, solange Ihr Server es bekommen kann:

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

und

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

Die Option "Wo", die nicht alle Dolmetscher kennen, sollte möglicherweise vermieden werden. Und natürlich ist die Ein-Klausel klarer.


-5

Das ist meine Lösung.

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

Sie müssen dieGROUP BY es zur Arbeit kommen.

Ich hoffe das hilft.


10
Das Gruppieren nur von songs.fullname, während Sie gleichzeitig song_id und singers.fullname auswählen, ist in den meisten Datenbanken ein Problem.
Btilly
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.