Domanda

Dopo averlo letto, questo non è un duplicato di Explicit vs Join SQL impliciti . La risposta può essere correlata (o anche la stessa) ma la domanda è diversa.


Qual è la differenza e cosa dovrebbe andare in ciascuna?

Se capisco correttamente la teoria, Query Optimizer dovrebbe essere in grado di utilizzare entrambi in modo intercambiabile.

È stato utile?

Soluzione

Non sono la stessa cosa.

Considera queste query:

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

e

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

Il primo restituirà un ordine e le relative righe, se presenti, per il numero dell'ordine 12345. Il secondo restituirà tutti gli ordini, ma solo l'ordine INNER JOIN avrà tutte le righe associate.

Con un <=>, le clausole sono effettivamente equivalenti. Tuttavia, solo perché sono funzionalmente uguali, in quanto producono gli stessi risultati, non significa che i due tipi di clausole abbiano lo stesso significato semantico.

Altri suggerimenti

  • Non importa per i join interni
  • Questioni relative ai join esterni

    a. WHERE clausola: Dopo iscrizione. I record verranno filtrati dopo che si è verificato il join.

    b. ON clausola - Prima iscrizione. I record (dalla tabella a destra) verranno filtrati prima di unirsi. Questo può risultare nullo nel risultato (dal momento che OUTER join).


Esempio : considera le tabelle seguenti:

    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) All'interno della clausola JOIN:

  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) All'interno della <=> clausola

  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 | 

Su INNER JOIN s sono intercambiabili e l'ottimizzatore li riorganizzerà a piacimento.

Su OUTER JOIN s, non sono necessariamente intercambiabili, a seconda del lato del join da cui dipendono.

Li metto in uno dei due posti a seconda della leggibilità.

Il modo in cui lo faccio è:

  • Metti sempre le condizioni di join nella clausola ON se stai facendo un INNER JOIN. Quindi, non aggiungere alcuna condizione WHERE alla clausola ON, inseriscile nella WHERE clausola.

  • Se si sta eseguendo un LEFT JOIN, aggiungere eventuali condizioni WHERE alla clausola WHERE t2.idfield IS NULL per la tabella nella parte destra del join. Questo è un must, perché l'aggiunta di una clausola WHERE che fa riferimento al lato destro del join convertirà il join in un JOIN INNER.

    L'eccezione è quando stai cercando i record che non si trovano in una particolare tabella. Aggiungere il riferimento a un identificatore univoco (che non è mai NULL) nella tabella RIGHT JOIN alla clausola WHERE in questo modo: <=>. Pertanto, l'unica volta in cui è necessario fare riferimento a una tabella sul lato destro del join è trovare i record che non si trovano nella tabella.

Su un join interno, significano la stessa cosa. Tuttavia, si otterranno risultati diversi in un join esterno a seconda se si inserisce la condizione di join nella clausola WHERE vs ON. Dai un'occhiata a questa domanda correlata e questa risposta (da me) .

Penso che abbia più senso avere l'abitudine di mettere sempre la condizione di join nella clausola ON (a meno che non sia un join esterno e in realtà non lo desideri nella clausola where) in quanto lo rende più chiaro a chiunque leggere la query su quali condizioni vengono unite le tabelle e aiuta anche a evitare che la clausola WHERE sia lunga dozzine di righe.

Questo articolo spiega chiaramente la differenza. Spiega anche il & Quot; ON join_condition vs WHERE join_condition o join_alias è null & Quot ;.

La clausola WHERE filtra il risultato della clausola FROM insieme ai JOIN mentre la clausola ON viene utilizzata per produrre il risultato della tabella tra le tabelle FROM e JOIN.

  1. Se si desidera produrre un risultato di tabella che unisce due tabelle, è necessario utilizzare la clausola ON per determinare la modalità di unione delle tabelle. Naturalmente, questo può anche filtrare le righe dalla tabella originale nel caso di un INNER JOIN, per esempio.
  2. Se si desidera filtrare il prodotto di unire entrambi i lati, è necessario utilizzare la clausola WHERE.

C'è una grande differenza tra dove clausola rispetto a sulla clausola , quando si tratta di unirsi a sinistra.

Ecco un esempio:

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

C'è fid id della tabella 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)

Query su " sulla clausola " :

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)

Query su " dove clausola " ;:

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)

È chiaro che, la prima query restituisce un record da t1 e la sua riga dipendente da t2, se presente, per la riga t1.v = 'K'.

La seconda query restituisce righe da t1, ma solo per t1.v = 'K' avrà una riga associata con essa.

In termini di ottimizzatore, non dovrebbe fare la differenza se si definiscono le clausole di join con ON o WHERE.

Tuttavia, IMHO, penso che sia molto più chiaro usare la clausola ON quando si eseguono join. In questo modo hai una sezione specifica della tua query che determina come viene gestita la join e mescolata con le altre clausole WHERE.

Penso che sia l'effetto della sequenza di join. Nel caso di join in alto a sinistra, SQL esegue prima il join sinistro e quindi il filtro. Nel caso negativo, trova prima Orders.ID = 12345, quindi unisciti.

Per un join interno, WHERE e ON possono essere utilizzati in modo intercambiabile. In effetti, è possibile utilizzare table1 in una sottoquery correlata. Ad esempio:

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

Questo è (IMHO) completamente confuso per un essere umano, ed è molto facile dimenticare di collegare <=> a qualsiasi cosa (perché la tabella " driver " non ha un " su " clausola), ma è legale.

per una migliore performance le tabelle dovrebbero avere una colonna indicizzata speciale da usare per JOINS.

quindi se la colonna su cui ti trovi non è una di quelle colonne indicizzate, sospetto che sia meglio tenerlo in DOVE.

quindi ti UNISCITI usando le colonne indicizzate, quindi dopo UNISCITI esegui la condizione sulla colonna nessuna indicizzata.

Normalmente, il filtro viene elaborato nella clausola WHERE una volta che le due tabelle sono già state unite. È possibile, anche se potresti voler filtrare una o entrambe le tabelle prima di unirle. vale a dire, la clausola where si applica all'intero set di risultati mentre la clausola on si applica solo al join in questione.

In SQL, le clausole 'WHERE' e 'ON' sono una sorta di Statemants condizionali, ma la differenza principale tra loro è, la clausola 'Where' viene usata nelle dichiarazioni Select / Update per specificare le Condizioni, mentre la ' ON 'La clausola viene utilizzata nei join, dove verifica o verifica se i record sono abbinati nelle tabelle di destinazione e di origine, prima che le tabelle vengano unite

Ad esempio: - "DOVE"

SELECT * FROM employee WHERE employee_id=101

Ad esempio: - "ON"

Esistono due tabelle impiegato e impiegato_dettagli, le colonne corrispondenti sono employee_id.

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

Spero di aver risposto alla tua domanda. Ripristinare per eventuali chiarimenti.

Consideriamo quelle tabelle:

A

id | SomeData

B

id | id_A | SomeOtherData

id_A essendo una chiave esterna per la tabella A

Scrittura di questa query:

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

Fornirà questo risultato:

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

Ciò che è in A ma non in B significa che ci sono valori nulli per B.


Ora, consideriamo una parte specifica in B.id_A ed evidenziamola dal risultato precedente:

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

Scrittura di questa query:

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

Fornirà questo risultato:

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

Perché ciò rimuove nell'unione interna i valori che non sono in B.id_A = SpecificPart


Ora, cambiamo la query in questo:

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

Il risultato è ora:

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

Poiché l'intero risultato viene filtrato in base a B.id_A = NULL rimozione delle parti <=>, che si trovano nella A che non sono in B

Stai cercando di unire i dati o filtrarli?

Per motivi di leggibilità ha più senso isolare questi casi d'uso rispettivamente su ON e WHERE.

  • unisci i dati in ON
  • filtra i dati in WHERE

Può diventare molto difficile leggere una query in cui la condizione JOIN e una condizione di filtro esistono nella clausola WHERE.

Per quanto riguarda le prestazioni, non dovresti vedere alcuna differenza, anche se a volte diversi tipi di SQL gestiscono la pianificazione delle query in modo diverso, quindi vale la pena provare ¯\_(ツ)_/¯ (tieni presente che la memorizzazione nella cache influisce sulla velocità della query)

Inoltre, come altri hanno notato, se si utilizza un join esterno si otterranno risultati diversi se si inserisce la condizione del filtro nella clausola ON perché ha effetto solo su una delle tabelle.

Ho scritto un post più approfondito su questo qui: https://dataschool.com/learn/difference-between- dove-e-on-a-sql

Penso che questa distinzione possa essere meglio spiegata tramite ordine logico delle operazioni in SQL , che è semplificato:

  • FROM (compresi i join)
  • WHERE
  • GROUP BY
  • Le aggregazioni
  • HAVING
  • WINDOW
  • SELECT
  • DISTINCT
  • UNION, INTERSECT, EXCEPT
  • ORDER BY
  • OFFSET
  • FETCH

I join non sono una clausola dell'istruzione select, ma un operatore all'interno di ON. Pertanto, tutte le JOIN clausole appartenenti al corrispondente LEFT JOIN operatore hanno & Quot; già avvenuta & Quot; logicamente quando l'elaborazione logica raggiunge la clausola FILM_ID. Ciò significa che nel caso di un NULL, ad esempio, la semantica del join esterno è già avvenuta prima dell'applicazione della clausola FILM_ID < 10.

Ho spiegato più dettagliatamente il seguente esempio in questo post del blog . Quando si esegue questa query:

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;

Il <=> non ha davvero alcun effetto utile, perché anche se un attore non ha recitato in un film, l'attore verrà filtrato, poiché il suo <=> sarà <=> e la clausola <=> filtrerà tale riga. Il risultato è qualcosa del tipo:

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

vale a dire. proprio come se noi interni ci unissimo ai due tavoli. Se spostiamo il predicato del filtro nella clausola <=>, ora diventa un criterio per il join esterno:

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;

Significa che il risultato conterrà attori senza film o senza film con <=>

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

In breve

Metti sempre il tuo predicato dove ha più senso, logicamente.

questa è la mia soluzione.

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

Devi avere il GROUP BY per farlo funzionare.

Spero che questo aiuto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top