Esta é uma pergunta muito comum, portanto, esta resposta é baseada neste artigo que escrevi.
Relação de tabela
Considerando que temos o seguinte post
e post_comment
tabelas:
O post
possui os seguintes registros:
| id | title |
|----|-----------|
| 1 | Java |
| 2 | Hibernate |
| 3 | JPA |
e o post_comment
tem 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 post
e post_comment
registros:
| 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 post
seus post_comment
registros. As post
linhas que não têm associação post_comment
sã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.