SQL JOIN - clausola WHERE vs. clausola ON


690

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


Qual è la differenza e cosa dovrebbe andare in ciascuno?

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


2
Solo per i futuri lettori e le tue informazioni dovresti leggere l'ordine di esecuzione di sql. Questo ti aiuterebbe più precisamente a comprendere la differenza di fondo.
Rahul Neekhra,

Risposte:


871

Non sono la stessa cosa.

Considera queste domande:

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 all'ordine 12345saranno associate delle righe.

Con un INNER JOIN, 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.


83
otterrai prestazioni migliori inserendo la clausola where nella clausola "on" per un join interno?
FistOfFury

96
@FistOfFury Sql Server utilizza una procedura di Query Optimizer che compila e valuta il codice per produrre il miglior piano di esecuzione possibile. Non è perfetto, ma il più delle volte non importa e otterrai lo stesso piano di esecuzione in entrambi i modi.
Joel Coehoorn,

18
In Postgres ho notato che NON erano equivalenti e hanno portato a piani di query diversi. Se si utilizza ON, si è verificato l'uso di materialize. Se hai usato DOVE, ha usato un hash. Il materializzare aveva un caso peggiore che era 10 volte più costoso dell'hash. Stava utilizzando un set di ID anziché un singolo ID.
JamesHutchison

13
@JamesHutchison È difficile fare generalizzazioni delle prestazioni affidabili basate su comportamenti osservati come questo. Ciò che era vero un giorno tende ad essere sbagliato il prossimo, perché si tratta di un dettaglio di implementazione piuttosto che di un comportamento documentato. I team di database sono sempre alla ricerca di luoghi per migliorare le prestazioni dell'ottimizzatore. Sarò sorpreso se il comportamento ON non migliora per adattarsi a WHERE. Potrebbe anche non apparire da nessuna parte nelle note di rilascio da una versione all'altra oltre a qualcosa come "miglioramenti generali delle prestazioni.
Joel Coehoorn,

4
@FiHoran Non è così che funziona Sql Server. Pre-filtrerà in modo aggressivo in base agli elementi della clausola WHERE quando le statistiche dimostrano che può essere utile.
Joel Coehoorn,

364
  • Non importa per i join interni
  • Questioni per i join esterni

    un. WHEREclausola: dopo l' adesione. I record verranno filtrati dopo il join.

    b. ONclausola - Prima di aderire. I record (dalla tabella a destra) verranno filtrati prima di unirsi. Questo può risultare nullo nel risultato (dal join OUTER).



Esempio : considerare 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) WHEREClausola interna :

  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) JOINClausola interna

  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 questa è la risposta migliore perché dimostra chiaramente cosa sta succedendo "sotto il cofano" delle altre risposte popolari.
psrpsrpsr,

1
Ottima spiegazione .... ben realizzata! - Solo curioso cosa hai fatto per ottenerlo intermediate join table? Qualche comando "Spiega"?
Manuel Jordan,

1
@ManuelJordan No, questo è solo per spiegazione. Un database può fare qualcosa di più performante che creare una tabella intermedia.
Sandeep Jindal,

Capito, supponevo che forse fosse usato un terzo strumento.
Manuel Jordan,

146

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

Su OUTER JOINs, non sono necessariamente intercambiabili, a seconda del lato da cui dipendono.

Li metto in entrambi i posti a seconda della leggibilità.



Probabilmente è molto più chiaro nella clausola Where, specialmente nelle espressioni 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

Il modo in cui lo faccio è:

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

  • Se si sta eseguendo una LEFT JOIN, aggiungere eventuali condizioni WHERE alla ONclausola 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. Si dovrebbe aggiungere il riferimento a un identificatore univoco (che non è mai NULL) nella RIGHT JOIN tabella per la clausola WHERE in questo modo: WHERE t2.idfield IS NULL. Pertanto, l'unica volta in cui è necessario fare riferimento a una tabella sul lato destro del join è trovare quei record che non si trovano nella tabella.


8
Questa è la migliore risposta che ho letto finora. Totalmente senso una volta che il vostro cervello capisce un LEFT JOIN è andando a restituire tutte le righe della tabella a sinistra e si deve filtrare in un secondo momento.
Nick Larsen,

se esternamente si unisce a una tabella con una colonna nullable, allora è ancora possibile "dove" essere nulla quella colonna senza renderla un join interno? Ciò non sta esattamente cercando i record che non si trovano solo in una tabella particolare. Puoi cercare 1. inesistente 2. non ha alcun valore.
Vicino

Voglio dire, puoi cercare entrambi: "1. non esisteva 2. non ha alcun valore" insieme. E questo vale nel caso in cui quel campo non sia inattivo.
Vicino

Come ho riscontrato questo caso: cercare partecipanti tra cui matricola (dati non ancora immessi) senza un contatto di emergenza.
Vicino

30

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 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 legga la tua query su quali condizioni vengono unite le tabelle e aiuta anche a evitare che la clausola WHERE sia lunga dozzine di righe.


26

Questa è una domanda molto comune, quindi questa risposta si basa su questo articolo che ho scritto.

Relazione al tavolo

Considerando che abbiamo le seguenti poste le post_commenttabelle:

Le tabelle <code> post </code> e <code> post_comment </code>

L' postha i seguenti record:

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

e il post_commentha le seguenti tre righe:

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

SQL INNER JOIN

La clausola JOIN SQL consente di associare righe appartenenti a tabelle diverse. Ad esempio, a CROSS JOIN creerà un prodotto cartesiano contenente tutte le possibili combinazioni di righe tra le due tabelle di giunzione.

Mentre CROSS JOIN è utile in alcuni scenari, la maggior parte delle volte, si desidera unire le tabelle in base a una condizione specifica. Ed è qui che entra in gioco INNER JOIN.

SQL INNER JOIN ci consente di filtrare il prodotto cartesiano dall'unione di due tabelle in base a una condizione specificata tramite la clausola ON.

SQL INNER JOIN - ON condizione "sempre vera"

Se si fornisce una condizione "sempre vera", INNER JOIN non filtrerà i record uniti e il set di risultati conterrà il prodotto cartesiano delle due tabelle di unione.

Ad esempio, se eseguiamo la seguente query SQL INNER JOIN:

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

Otterremo tutte le combinazioni poste i post_commentrecord:

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

Pertanto, se la condizione della clausola ON è "sempre vera", INNER JOIN è semplicemente equivalente a una query 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 Condizione "sempre falso"

D'altra parte, se la condizione della clausola ON è "sempre falsa", tutti i record uniti verranno filtrati e il set di risultati sarà vuoto.

Quindi, se eseguiamo la seguente query SQL INNER JOIN:

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

Non otterremo alcun risultato indietro:

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

Questo perché la query sopra è equivalente alla seguente query CROSS JOIN:

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 - clausola ON che utilizza le colonne Chiave esterna e Chiave primaria

La condizione della clausola ON più comune è quella che corrisponde alla colonna Chiave esterna nella tabella figlio con la colonna Chiave primaria nella tabella padre, come illustrato dalla seguente query:

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

Quando si esegue la query SQL INNER JOIN sopra riportata, si ottiene il seguente set di risultati:

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

Pertanto, solo i record che corrispondono alla condizione della clausola ON sono inclusi nel set di risultati della query. Nel nostro caso, il set di risultati contiene tutte le postinsieme con i loro post_commentdischi. Le postrighe che non post_commentsono associate sono escluse poiché non possono soddisfare la condizione della clausola ON.

Ancora una volta, la query SQL INNER JOIN sopra riportata equivale alla seguente query CROSS JOIN:

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

Le righe non colpite sono quelle che soddisfano la clausola WHERE e solo questi record verranno inclusi nel set di risultati. Questo è il modo migliore per visualizzare come funziona la clausola INNER JOIN.

| p.id | pc.post_id | pc.id | p.title | pc.review |
| ------ | ------------ | ------- | ----------- | --------- - |
| 1 | 1 | 1 | Java | Buono |
| 1 | 1 | 2 | Java | Eccellente |
| 1 | 2 | 3 | Java | Fantastico | 
| 2 | 1 | 1 | Ibernazione | Buono | 
| 2 | 1 | 2 | Ibernazione | Eccellente |
| 2 | 2 | 3 | Ibernazione | Fantastico |
| 3 | 1 | 1 | JPA | Buono | 
| 3 | 1 | 2 | JPA | Eccellente | 
| 3 | 2 | 3 | JPA | Fantastico |

Conclusione

Un'istruzione INNER JOIN può essere riscritta come CROSS JOIN con una clausola WHERE che corrisponde alla stessa condizione utilizzata nella clausola ON della query INNER JOIN.

Non che ciò si applichi solo a INNER JOIN, non a OUTER JOIN.


11

C'è una grande differenza tra cui la clausola contro il clausola , quando si tratta di aderire 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    |       |
+-------+-------------+------+-----+---------+-------+

È presente l'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 "on 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)

Interrogazione su "clausola 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)

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


9

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 l'unione e mescolata con le altre clausole WHERE.


7

Consideriamo quelle tabelle:

UN

id | SomeData

B

id | id_A | SomeOtherData

id_A essendo una chiave esterna per la tabella A

Scrivere 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_Ae evidenziamola dal risultato precedente:

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

Scrivere 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 presenti 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 modo da non B.id_A = SpecificPartrimuovere le parti B.id_A = NULL, che si trovano nella A che non si trovano nella B.


4

Stai cercando di unire i dati o filtrare i dati?

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

  • unire i dati in ON
  • filtra i dati in DOVE

Può diventare molto difficile leggere una query in cui esistono la condizione JOIN e una condizione di filtro 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 ¯\_(ツ)_/¯ (fai attenzione alla memorizzazione nella cache che 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 di 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-where-and-on-in-sql


2

In SQL, le clausole "WHERE" e "ON" sono una sorta di Statemants condizionali, ma la principale differenza è la clausola "Where" nelle istruzioni Select / Update per specificare le condizioni, mentre la clausola "ON" viene utilizzato in Join, dove verifica o controlla 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"

Ci sono due tabelle impiegati e impiegati_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.


Ma potresti usare la parola chiave WHEREal posto di ON, vero? sqlfiddle.com/#!2/ae5b0/14/0
Qwerty,

1

Penso che sia l'effetto sequenza 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 esegui l'unione.


1

Per un join interno WHEREe ONpuò essere utilizzato in modo intercambiabile. In effetti, è possibile utilizzare ONin una sottoquery correlata. Per 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) è assolutamente confuso per un essere umano, ed è molto facile dimenticare di collegarsi table1a qualsiasi cosa (perché la tabella "driver" non ha una clausola "on"), ma è legale.


1

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, allora sospetto che sia meglio tenerlo in DOVE.

quindi ISCRIVITI utilizzando le colonne indicizzate, quindi dopo JOIN esegui la condizione sulla colonna nessuna indicizzata.


1

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.


Questo non è così poiché i DBMS "normalmente" ottimizzano.
philipxy,

1

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

  • FROM (compresi i join)
  • WHERE
  • GROUP BY
  • 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 FROM . Pertanto, tutte le ONclausole appartenenti JOINall'operatore corrispondente sono "già avvenute" logicamente quando l'elaborazione logica raggiunge la WHEREclausola. Ciò significa che, nel caso di a LEFT JOIN, ad esempio, la semantica del join esterno è già avvenuta al momento dell'applicazione della WHEREclausola.

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 LEFT JOIN realtà non hanno alcun effetto utile, perché anche se un attore non ha giocato in un film, l'attore sarà filtrato, come FILM_IDsarà NULLe la WHEREclausola filtrerà tali righe a. Il risultato è qualcosa di simile:

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 come se noi interni ci unissimo ai due tavoli. Se spostiamo il predicato del filtro nella ONclausola, 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;

Ciò significa che il risultato conterrà attori senza film o film 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

In breve

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


0

Per quanto riguarda la tua domanda,

È lo stesso sia "on" che "where" su un join interno, a condizione che il server lo riesca:

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

e

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

L'opzione 'dove' non tutti gli interpreti sanno, quindi forse dovrebbe essere evitata. E ovviamente la clausola "on" è più chiara.


-5

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 ilGROUP BY permesso di farlo funzionare.

Spero che questo aiuto.


10
Raggruppare solo song.fullname mentre si seleziona anche song_id e singers.fullname sarà un problema nella maggior parte dei database.
btilly
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.