SQL JOIN - cláusula WHERE vs. cláusula ON

686

Após a leitura, isso não é uma duplicata das junções explícitas vs implícitas do SQL . A resposta pode estar relacionada (ou mesmo a mesma), mas a pergunta é diferente.


Qual é a diferença e o que deve acontecer em cada uma?

Se eu entendi a teoria corretamente, o otimizador de consulta deve poder usar os dois de forma intercambiável.

BCS
fonte
2
Apenas para futuros leitores e suas informações, você deve ler a ordem de execução do sql. Isso ajudaria você a entender com mais precisão a diferença subjacente.
Rahul Neekhra

Respostas:

869

Eles não são a mesma coisa.

Considere estas consultas:

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

O primeiro retornará um pedido e suas linhas, se houver, para o número do pedido 12345. O segundo retornará todos os pedidos, mas somente o pedido 12345terá linhas associadas a ele.

Com um INNER JOIN, as cláusulas são efetivamente equivalentes. No entanto, apenas porque eles são funcionalmente iguais, na medida em que produzem os mesmos resultados, não significa que os dois tipos de cláusulas tenham o mesmo significado semântico.

Joel Coehoorn
fonte
83
você obterá melhor desempenho colocando a cláusula where na cláusula "on" para uma junção interna?
FistOfFury
96
O @FistOfFury Sql Server usa um procedimento de otimizador de consulta que compila e avalia seu código para produzir o melhor plano de execução possível. Não é perfeito, mas na maioria das vezes não importa e você obterá o mesmo plano de execução de qualquer maneira.
Joel Coehoorn
18
No Postgres, observei que eles NÃO eram equivalentes e resultaram em diferentes planos de consulta. Se você usar ON, resultou no uso de materialize. Se você usou WHERE, ele usou um hash. O materialize teve um caso pior que foi 10 vezes mais caro que o hash. Isso estava usando um conjunto de IDs em vez de um único ID.
21416 JamesHutchison
13
@JamesHutchison É difícil fazer generalizações de desempenho confiáveis ​​com base em comportamentos observados como este. O que era verdade um dia tende a estar errado no dia seguinte, porque esse é um detalhe da implementação e não um comportamento documentado. As equipes de banco de dados estão sempre procurando lugares para melhorar o desempenho do otimizador. Ficarei surpreso se o comportamento ON não melhorar para corresponder ao WHERE. Pode até não aparecer em qualquer lugar em notas de lançamento de versão para versão que não seja algo como "melhorias de desempenho geral.
Joel Coehoorn
4
@FiHoran Não é assim que o Sql Server funciona. Ele pré-filtrará agressivamente com base nos itens da cláusula WHERE quando as estatísticas mostrarem que pode ser útil.
Joel Coehoorn
362
  • Não importa para junções internas
  • Matérias para junções externas

    uma. WHEREcláusula: Após ingressar. Os registros serão filtrados após a associação.

    b. ONCláusula - Antes de ingressar. Os registros (da tabela à direita) serão filtrados antes da associação. Isso pode acabar como nulo no resultado (desde a junção OUTER).



Exemplo : considere as tabelas abaixo:

    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) WHERECláusula 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) JOINCláusula 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 | 
Sandeep Jindal
fonte
40
Na OMI, essa é a melhor resposta, pois demonstra claramente o que está acontecendo "sob o capô" das outras respostas populares.
Psrpsrpsr 15/05
1
Excelente explicação .... bem feito! - Só curioso, o que você fez para conseguir isso intermediate join table? Algum comando 'Explain'?
Manuel Jordan
1
@ManuelJordan Não, isso é apenas uma explicação. Um banco de dados pode fazer algo mais eficiente do que criar uma tabela intermediária.
Sandeep Jindal
Entendido, presumi que talvez uma terceira ferramenta fosse usada.
Manuel Jordan
145

Em INNER JOINs, eles são intercambiáveis ​​e o otimizador os reorganizará à vontade.

Em OUTER JOINs, eles não são necessariamente intercambiáveis, dependendo de qual lado da junção eles dependem.

Coloquei-os em qualquer lugar, dependendo da legibilidade.

Cade Roux
fonte
É provavelmente muito mais claro na cláusula WHERE, especialmente em LINQ to Entities expressões lambdaOrders.Join( OrderLines, x => x.ID, x => OrderID, (o,l) => new {Orders = o, Lines = l}).Where( ol => ol.Orders.ID = 12345)
Triynko
49

O jeito que eu faço é:

  • Sempre coloque as condições de junção na ONcláusula se você estiver executando um INNER JOIN. Portanto, não inclua nenhuma condição WHERE na cláusula ON, coloque-a na WHEREcláusula

  • Se você estiver fazendo a LEFT JOIN, adicione quaisquer condições WHERE à ONcláusula da tabela no lado direito da junção. Isso é obrigatório, pois adicionar uma cláusula WHERE que faça referência ao lado direito da junção converterá a junção em INNER JOIN.

    A exceção é quando você está procurando os registros que não estão em uma tabela específica. Você gostaria de acrescentar a referência a um identificador único (que não é sempre NULL) na RIGHT JOIN tabela para a cláusula WHERE da seguinte forma: WHERE t2.idfield IS NULL. Portanto, a única vez em que você deve fazer referência a uma tabela no lado direito da junção é encontrar os registros que não estão na tabela.

HLGEM
fonte
8
Esta é a melhor resposta que li sobre isso até agora. Totalmente faz sentido uma vez que seu cérebro compreende um LEFT JOIN está indo para retornar todas as linhas na tabela esquerda e você tem que filtrá-la mais tarde.
Nick Larsen
se você associar externamente uma tabela com uma coluna anulável, ainda poderá "onde" essa coluna ser nula sem torná-la uma associação interna? Isso não está exatamente procurando os registros que não estão apenas em uma tabela específica. Você pode procurar 1. não existe 2. não tem valor algum.
Perto de
Quero dizer, você pode procurar pelos dois: "1. não existe 2. não tem valor" juntos. E isso se aplica ao caso em que esse campo não é idfield.
Perto de
Como encontrei este caso: procurando participantes, incluindo calouros (dados ainda não inseridos) sem um contato de emergência.
Perto de
30

Em uma junção interna, eles significam a mesma coisa. No entanto, você obterá resultados diferentes em uma associação externa, dependendo se você colocar a condição de associação na cláusula WHERE vs ON. Dê uma olhada nesta pergunta relacionada e nesta resposta (por mim).

Eu acho que faz mais sentido ter o hábito de sempre colocar a condição de junção na cláusula ON (a menos que seja uma junção externa e você realmente a queira na cláusula where), pois fica mais claro para quem lê sua consulta em que condições as tabelas estão sendo unidas e também ajuda a impedir que a cláusula WHERE tenha dezenas de linhas.

matt b
fonte
26

Esta é uma pergunta muito comum, portanto, esta resposta é baseada neste artigo que escrevi.

Relação de tabela

Considerando que temos o seguinte poste post_commenttabelas:

As tabelas <code> post </code> e <code> post_comment </code>

O postpossui os seguintes registros:

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

e o post_commenttem as seguintes três linhas:

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

SQL INNER JOIN

A cláusula SQL JOIN permite associar linhas que pertencem a tabelas diferentes. Por exemplo, um CROSS JOIN criará um produto cartesiano contendo todas as combinações possíveis de linhas entre as duas tabelas de junção.

Embora o CROSS JOIN seja útil em determinados cenários, na maioria das vezes, você deseja ingressar em tabelas com base em uma condição específica. E é aí que o INNER JOIN entra em cena.

O SQL INNER JOIN nos permite filtrar o produto cartesiano da união de duas tabelas com base em uma condição especificada através da cláusula ON.

SQL INNER JOIN - ON "condição sempre verdadeira"

Se você fornecer uma condição "sempre verdadeira", o INNER JOIN não filtrará os registros unidos e o conjunto de resultados conterá o Produto Cartesiano das duas tabelas de junção.

Por exemplo, se executarmos a seguinte consulta 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

Obteremos todas as combinações de poste post_commentregistros:

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

Portanto, se a condição da cláusula ON for "sempre verdadeira", o INNER JOIN será simplesmente equivalente a uma consulta 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 "condição sempre falsa"

Por outro lado, se a condição da cláusula ON for "sempre falsa", todos os registros associados serão filtrados e o conjunto de resultados ficará vazio.

Portanto, se executarmos a seguinte consulta 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

Não obteremos nenhum resultado de volta:

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

Isso ocorre porque a consulta acima é equivalente à seguinte consulta 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

Cláusula SQL INNER JOIN - ON usando as colunas Chave Externa e Chave Primária

A condição da cláusula ON mais comum é aquela que corresponde à coluna Chave estrangeira na tabela filha com a coluna Chave primária na tabela pai, conforme ilustrado pela seguinte consulta:

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

Ao executar a consulta SQL INNER JOIN acima, obtemos o seguinte conjunto de resultados:

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

Portanto, apenas os registros que correspondem à condição da cláusula ON são incluídos no conjunto de resultados da consulta. No nosso caso, o conjunto de resultados contém todos os postseus post_commentregistros. As postlinhas que não têm associação post_commentsão excluídas, pois não podem satisfazer a condição da cláusula ON.

Novamente, a consulta SQL INNER JOIN acima é equivalente à seguinte consulta 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

As linhas não marcadas são as que satisfazem a cláusula WHERE, e somente esses registros serão incluídos no conjunto de resultados. Essa é a melhor maneira de visualizar como a cláusula INNER JOIN funciona.

| p.id pc.post_id | pc.id | p.title | pc.review |
| ------ | ------------ | ------- | ----------- | --------- - |
| 1 | 1 | 1 | Java Bom
| 1 | 1 | 2 Java Excelente
| 1 | 2 3 Java Impressionante | 
| 2 1 | 1 | Hibernação Bom 
| 2 1 | 2 Hibernação Excelente
| 2 2 3 Hibernação Impressionante |
| 3 1 | 1 | JPA Bom 
| 3 1 | 2 JPA Excelente 
| 3 2 3 JPA Impressionante |

Conclusão

Uma instrução INNER JOIN pode ser reescrita como CROSS JOIN com uma cláusula WHERE que corresponde à mesma condição usada na cláusula ON da consulta INNER JOIN.

Não que isso se aplique apenas a INNER JOIN, não a OUTER JOIN.

Vlad Mihalcea
fonte
11

Há uma grande diferença entre a cláusula where vs. on , quando se trata da junção esquerda.

Aqui está um exemplo:

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

Há fid é id da tabela 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)

Consulta sobre "na cláusula":

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)

Consulta na "cláusula 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)

É claro que, a primeira consulta retorna um registro de t1 e sua linha dependente de t2, se houver, para a linha t1.v = 'K'.

A segunda consulta retorna linhas de t1, mas apenas para t1.v = 'K' terá qualquer linha associada a ela.

Hrishikesh Mishra
fonte
9

Em termos do otimizador, não deve fazer diferença se você define suas cláusulas de junção com ON ou WHERE.

No entanto, IMHO, acho muito mais claro usar a cláusula ON ao executar junções. Dessa forma, você tem uma seção específica de sua consulta que determina como a junção é manipulada versus misturada com o restante das cláusulas WHERE.

Grant Limberg
fonte
7

Vamos considerar essas tabelas:

UMA

id | SomeData

B

id | id_A | SomeOtherData

id_A sendo uma chave estrangeira para a tabela A

Escrevendo esta consulta:

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

Fornecerá este resultado:

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

O que está em A, mas não em B, significa que há valores nulos para B.


Agora, vamos considerar uma parte específica B.id_Ae destacá-la do resultado anterior:

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

Escrevendo esta consulta:

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

Fornecerá este resultado:

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

Como isso remove na junção interna os valores que não estão no B.id_A = SpecificPart


Agora, vamos mudar a consulta para isso:

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

O resultado é agora:

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

Como todo o resultado é filtrado contra a B.id_A = SpecificPartremoção das peças B.id_A = NULL, que estão no A que não estão no B

Cid
fonte
4

Você está tentando juntar dados ou filtrar dados?

Para facilitar a leitura, faz mais sentido isolar esses casos de uso como ON e WHERE, respectivamente.

  • juntar dados em ON
  • filtrar dados em WHERE

Pode ser muito difícil ler uma consulta em que a condição JOIN e a condição de filtragem existam na cláusula WHERE.

Em termos de desempenho, você não deve ver a diferença, embora tipos diferentes de SQL às vezes lidem com o planejamento de consultas de maneira diferente, para que possa valer a pena tentar ¯\_(ツ)_/¯(lembre-se do cache afetando a velocidade da consulta)

Além disso, como outros observaram, se você usar uma junção externa, obterá resultados diferentes se colocar a condição de filtro na cláusula ON porque ela afeta apenas uma das tabelas.

Escrevi um post mais detalhado sobre isso aqui: https://dataschool.com/learn/difference-between-where-and-on-in-sql

Matthew David
fonte
2

No SQL, a cláusula 'WHERE' e 'ON' são tipos de Statemants Condicionais, mas a principal diferença entre eles é a cláusula 'Where' que é usada nas Instruções de Seleção / Atualização para especificar as Condições, enquanto a cláusula 'ON' é usado em Junções, onde verifica ou verifica se os Registros são Correspondidos nas tabelas de destino e de origem, antes que as Tabelas sejam Associadas

Por exemplo: - 'WHERE'

SELECT * FROM employee WHERE employee_id=101

Por exemplo: - 'ON'

Existem duas tabelas employee e employee_details, as colunas correspondentes são employee_id.

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

Espero ter respondido sua pergunta. Reverta para qualquer esclarecimento.

Sharon Fernando
fonte
Mas você pode usar a palavra-chave WHEREno lugar de ON, não é? sqlfiddle.com/#!2/ae5b0/14/0
Qwerty
1

Eu acho que é o efeito da sequência de junção. No caso de junção superior esquerda, o SQL faz a junção esquerda primeiro e depois faz o filtro. No caso inferior, localize Orders.ID = 12345 primeiro e depois ingresse.

Xing-Wei Lin
fonte
1

Para uma junção interna, WHEREe ONpode ser usado de forma intercambiável. De fato, é possível usar ONem uma subconsulta correlacionada. Por exemplo:

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

Isso é (IMHO) totalmente confuso para um humano, e é muito fácil esquecer de vincular table1a qualquer coisa (porque a tabela "driver" não possui uma cláusula "on"), mas é legal.

Austin Barry
fonte
1

para obter um melhor desempenho, as tabelas devem ter uma coluna indexada especial a ser usada para JOINS.

Portanto, se a coluna que você condicionar não for uma daquelas colunas indexadas, suspeito que seja melhor mantê-la em WHERE.

para que você JOIN use as colunas indexadas, depois de JOIN, execute a condição na coluna nenhuma indexada.

yakoub abaya
fonte
1

Normalmente, a filtragem é processada na cláusula WHERE depois que as duas tabelas já foram unidas. É possível, embora você queira filtrar uma ou ambas as tabelas antes de ingressar nelas. ou seja, a cláusula where se aplica a todo o conjunto de resultados, enquanto a cláusula on se aplica apenas à junção em questão.

sree
fonte
Isso não é verdade, já que os DBMSs "otimizam" normalmente.
philipxy
1

Eu acho que essa distinção pode ser melhor explicada através da ordem lógica das operações no SQL , que é simplificada:

  • FROM (incluindo junções)
  • WHERE
  • GROUP BY
  • Agregações
  • HAVING
  • WINDOW
  • SELECT
  • DISTINCT
  • UNION, INTERSECT,EXCEPT
  • ORDER BY
  • OFFSET
  • FETCH

Associações não são uma cláusula da instrução select, mas um operador dentro de FROM. Como tal, todas as ONcláusulas pertencentes ao JOINoperador correspondente "já aconteceram" logicamente quando o processamento lógico chega à WHEREcláusula. Isso significa que, no caso de uma LEFT JOIN, por exemplo, a semântica da junção externa já aconteceu no momento em que a WHEREcláusula é aplicada.

Expliquei o exemplo a seguir com mais detalhes nesta postagem do blog . Ao executar esta consulta:

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;

O LEFT JOINrealmente não tem qualquer efeito útil, porque, mesmo se um ator não jogar em um filme, o ator será filtrada, como FILM_IDserá NULLeo WHEREcláusula irá filtrar tais linha a. O resultado é algo como:

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

Ou seja, como se nos juntássemos às duas mesas. Se movermos o predicado de filtro na ONcláusula, ele se tornará um critério para a junção externa:

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;

Ou seja, o resultado conterá atores sem nenhum filme ou sem filmes com 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

Em resumo

Sempre coloque seu predicado onde faz mais sentido, logicamente.

Lukas Eder
fonte
0

Quanto à sua pergunta,

É o mesmo 'on' ou 'where' em uma junção interna, desde que o servidor possa obtê-lo:

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

e

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

A opção 'where' nem todos os intérpretes sabem, portanto talvez deva ser evitada. E, claro, a cláusula 'on' é mais clara.

Ezequiel
fonte
-5

Esta é a minha solução.

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

Você deve ter a GROUP BYobtê-lo para o trabalho.

Espero que esta ajuda.

Le Quang Chien
fonte
10
Agrupar apenas songs.fullname enquanto você também seleciona song_id e singers.fullname será um problema na maioria dos bancos de dados.
btilly