Respostas:
SQL JOIN
?SQL JOIN
é um método para recuperar dados de duas ou mais tabelas de banco de dados.
SQL JOIN
s?Há um total de cinco JOIN
s. Eles são :
1. JOIN or INNER JOIN
2. OUTER JOIN
2.1 LEFT OUTER JOIN or LEFT JOIN
2.2 RIGHT OUTER JOIN or RIGHT JOIN
2.3 FULL OUTER JOIN or FULL JOIN
3. NATURAL JOIN
4. CROSS JOIN
5. SELF JOIN
Nesse tipo de a JOIN
, obtemos todos os registros que correspondem à condição nas duas tabelas e os registros nas duas tabelas que não correspondem não são relatados.
Em outras palavras, INNER JOIN
é baseado no fato único de que: SOMENTE as entradas correspondentes em AMBAS as tabelas DEVEM ser listadas.
Note-se que um JOIN
sem quaisquer outras JOIN
palavras-chave (como INNER
, OUTER
, LEFT
, etc) é um INNER JOIN
. Em outras palavras, JOIN
é um açúcar sintático para INNER JOIN
(consulte: Diferença entre JOIN e INNER JOIN ).
OUTER JOIN
recupera
As linhas correspondentes de uma tabela e todas as linhas da outra tabela. Ou todas as linhas de todas as tabelas (não importa se existe ou não uma correspondência).
Existem três tipos de junção externa:
2.1 JOGO EXTERIOR ESQUERDO ou JOIN ESQUERDO
Essa junção retorna todas as linhas da tabela esquerda em conjunto com as linhas correspondentes da tabela direita. Se não houver colunas correspondentes na tabela à direita, ele retornará NULL
valores.
2.2 JUNÇÃO EXTERNA DIREITA ou JUNTA DIREITA
Isso JOIN
retorna todas as linhas da tabela direita em conjunto com as linhas correspondentes da tabela esquerda. Se não houver colunas correspondentes na tabela esquerda, ele retornará NULL
valores.
2.3 JUNÇÃO EXTERNA COMPLETA ou JUNÇÃO COMPLETA
Isso JOIN
combina LEFT OUTER JOIN
e RIGHT OUTER JOIN
. Retorna linhas de qualquer tabela quando as condições são atendidas e retorna NULL
valor quando não há correspondência.
Em outras palavras, OUTER JOIN
é baseado no fato de que: SOMENTE as entradas correspondentes em UMA DAS tabelas (DIREITA ou ESQUERDA) ou AMBAS as tabelas (CHEIA) DEVEM ser listadas.
Note that `OUTER JOIN` is a loosened form of `INNER JOIN`.
É baseado nas duas condições:
JOIN
é feito em todas as colunas com o mesmo nome para igualdade.Isso parece ser mais de natureza teórica e, como resultado (provavelmente), a maioria dos DBMS nem se dá ao trabalho de apoiar isso.
É o produto cartesiano das duas tabelas envolvidas. O resultado de a CROSS JOIN
não fará sentido na maioria das situações. Além disso, não precisaremos disso (ou precisa, no mínimo, para ser mais preciso).
Não é uma forma diferente de JOIN
, pelo contrário, é um JOIN
( INNER
, OUTER
, etc.) de uma mesa para si.
Dependendo do operador usado para uma JOIN
cláusula, pode haver dois tipos de JOIN
s. Eles são
Para qualquer JOIN
tipo ( INNER
, OUTER
etc), se usarmos SOMENTE o operador de igualdade (=), então dizemos que JOIN
é um EQUI JOIN
.
É o mesmo, EQUI JOIN
mas permite todos os outros operadores como>, <,> = etc.
Muitos consideram ambos
EQUI JOIN
e ThetaJOIN
semelhante aoINNER
,OUTER
etcJOIN
s. Mas acredito firmemente que é um erro e torna as idéias vagas. PorqueINNER JOIN
,OUTER JOIN
etc estão todos conectados com as tabelas e seus dados enquantoEQUI JOIN
eTHETA JOIN
só são conectados com os operadores que usamos no primeiro.Novamente, há muitos que consideram
NATURAL JOIN
algum tipo de "peculiar"EQUI JOIN
. De fato, é verdade, por causa da primeira condição que mencioneiNATURAL JOIN
. No entanto, não precisamos restringir isso simplesmente aNATURAL JOIN
s sozinho.INNER JOIN
s,OUTER JOIN
s etc também pode ser umEQUI JOIN
.
Definição:
JOINS são uma maneira de consultar os dados combinados de várias tabelas simultaneamente.
No que diz respeito ao RDBMS, existem 5 tipos de junções:
Equi-Join: combina registros comuns de duas tabelas com base na condição de igualdade. Tecnicamente, a Junta é feita usando o operador de igualdade (=) para comparar os valores da Chave Primária de uma tabela e da Chave Externa de outra tabela; portanto, o conjunto de resultados inclui registros comuns (correspondentes) das duas tabelas. Para implementação, consulte INNER-JOIN.
Junção natural: é uma versão aprimorada do Equi-Join, na qual a operação SELECT omite a coluna duplicada. Para implementação, consulte INNER-JOIN
Non-Equi-Join: É o inverso da Equi-join onde a condição de junção é diferente de operador igual (=), por exemplo,! =, <=,> =,>, <Ou ENTRE etc. Para implementação, consulte INNER-JOIN.
Auto- ingresso:: um comportamento personalizado de ingresso em que uma tabela se combina consigo mesma; Isso geralmente é necessário para consultar tabelas de auto-referência (ou entidade de relacionamento Unário). Para implementação, consulte INNER-JOINs.
Produto cartesiano: Cruz combina todos os registros de ambas as tabelas sem nenhuma condição. Tecnicamente, ele retorna o conjunto de resultados de uma consulta sem a cláusula WHERE.
De acordo com a preocupação e o avanço do SQL, existem três tipos de junções e todas as junções RDBMS podem ser obtidas usando esses tipos de junções.
INNER-JOIN: Mescla (ou combina) linhas correspondentes de duas tabelas. A correspondência é feita com base em colunas comuns de tabelas e sua operação de comparação. Se a condição baseada na igualdade, então: EQUI-JOIN for executada, caso contrário, não-EQUI-Join.
OUTER-JOIN: mescla (ou combina) linhas correspondentes de duas tabelas e linhas não correspondentes com valores NULL. No entanto, é possível customizar a seleção de linhas sem correspondência, por exemplo, selecionando a linha sem correspondência da primeira tabela ou da segunda tabela por sub-tipos: JUNÇÃO EXTERNA ESQUERDA e JUNÇÃO EXTERNA DIREITA.
2.1 LEFT Outer JOIN (também conhecido como LEFT-JOIN): Retorna linhas correspondentes de duas tabelas e não correspondentes da tabela LEFT (ou seja, primeira tabela).
2.2 JOIN externo à direita (também conhecido como JOINT à DIREITA): retorna linhas correspondentes de duas tabelas e não correspondentes apenas da tabela RIGHT.
2.3 JOGO EXTERNO COMPLETO (também conhecido como JOIN EXTERIOR): Retorna correspondidos e não correspondidos das duas tabelas.
CROSS-JOIN: Essa junção não mescla / combina, em vez disso, executa o produto cartesiano.
Nota: A auto-junção pode ser alcançada por INNER-JOIN, OUTER-JOIN e CROSS-JOIN com base no requisito, mas a tabela deve se unir.
1.1: INNER-JOIN: Implementação de Equi-join
SELECT *
FROM Table1 A
INNER JOIN Table2 B ON A.<Primary-Key> =B.<Foreign-Key>;
1.2: INNER-JOIN: Implementação Natural-JOIN
Select A.*, B.Col1, B.Col2 --But no B.ForeignKeyColumn in Select
FROM Table1 A
INNER JOIN Table2 B On A.Pk = B.Fk;
1.3: INNER-JOIN com implementação NÃO-Equi-join
Select *
FROM Table1 A INNER JOIN Table2 B On A.Pk <= B.Fk;
1.4: INNER-JOIN com SELF-JOIN
Select *
FROM Table1 A1 INNER JOIN Table1 A2 On A1.Pk = A2.Fk;
2.1: JUNÇÃO EXTERNA (junção externa completa)
Select *
FROM Table1 A FULL OUTER JOIN Table2 B On A.Pk = B.Fk;
2.2: JUNTA ESQUERDA
Select *
FROM Table1 A LEFT OUTER JOIN Table2 B On A.Pk = B.Fk;
2.3: JUNTA CERTA
Select *
FROM Table1 A RIGHT OUTER JOIN Table2 B On A.Pk = B.Fk;
3.1: JUNÇÃO TRANSVERSAL
Select *
FROM TableA CROSS JOIN TableB;
3.2: CROSS JOIN-Self JOIN
Select *
FROM Table1 A1 CROSS JOIN Table1 A2;
//OU//
Select *
FROM Table1 A1,Table1 A2;
intersect
/ except
/ union
; aqui os círculos são as linhas retornadas por left
& right
join
, como dizem os rótulos numerados. A imagem do AXB não faz sentido. cross join
= inner join on 1=1
& é um caso especial do primeiro diagrama.
UNION JOIN
. Agora tornado obsoleto no SQL: 2003.
Curiosamente, a maioria das outras respostas sofre com esses dois problemas:
Escrevi recentemente um artigo sobre o tópico: Um guia abrangente e provavelmente incompleto para as várias maneiras diferentes de ingressar em tabelas no SQL , que resumirei aqui.
É por isso que os diagramas de Venn os explicam de maneira tão imprecisa, porque um JOIN cria um produto cartesiano entre as duas tabelas unidas. A Wikipedia ilustra bem:
A sintaxe SQL para produtos cartesianos é CROSS JOIN
. Por exemplo:
SELECT *
-- This just generates all the days in January 2017
FROM generate_series(
'2017-01-01'::TIMESTAMP,
'2017-01-01'::TIMESTAMP + INTERVAL '1 month -1 day',
INTERVAL '1 day'
) AS days(day)
-- Here, we're combining all days with all departments
CROSS JOIN departments
Que combina todas as linhas de uma tabela com todas as linhas da outra tabela:
Fonte:
+--------+ +------------+
| day | | department |
+--------+ +------------+
| Jan 01 | | Dept 1 |
| Jan 02 | | Dept 2 |
| ... | | Dept 3 |
| Jan 30 | +------------+
| Jan 31 |
+--------+
Resultado:
+--------+------------+
| day | department |
+--------+------------+
| Jan 01 | Dept 1 |
| Jan 01 | Dept 2 |
| Jan 01 | Dept 3 |
| Jan 02 | Dept 1 |
| Jan 02 | Dept 2 |
| Jan 02 | Dept 3 |
| ... | ... |
| Jan 31 | Dept 1 |
| Jan 31 | Dept 2 |
| Jan 31 | Dept 3 |
+--------+------------+
Se apenas escrevermos uma lista de tabelas separadas por vírgula, obteremos o mesmo:
-- CROSS JOINing two tables:
SELECT * FROM table1, table2
An INNER JOIN
é apenas um filtro CROSS JOIN
onde o predicado de filtro é chamado Theta
na álgebra relacional.
Por exemplo:
SELECT *
-- Same as before
FROM generate_series(
'2017-01-01'::TIMESTAMP,
'2017-01-01'::TIMESTAMP + INTERVAL '1 month -1 day',
INTERVAL '1 day'
) AS days(day)
-- Now, exclude all days/departments combinations for
-- days before the department was created
JOIN departments AS d ON day >= d.created_at
Observe que a palavra INNER
- chave é opcional (exceto no MS Access).
( veja o artigo para exemplos de resultados )
Um tipo especial de Theta-JOIN é o equi JOIN, que mais usamos. O predicado associa a chave primária de uma tabela à chave estrangeira de outra tabela. Se usarmos o banco de dados Sakila para ilustração, podemos escrever:
SELECT *
FROM actor AS a
JOIN film_actor AS fa ON a.actor_id = fa.actor_id
JOIN film AS f ON f.film_id = fa.film_id
Isso combina todos os atores com seus filmes.
Ou também, em alguns bancos de dados:
SELECT *
FROM actor
JOIN film_actor USING (actor_id)
JOIN film USING (film_id)
A USING()
sintaxe permite especificar uma coluna que deve estar presente em ambos os lados das tabelas de uma operação JOIN e cria um predicado de igualdade nessas duas colunas.
Outras respostas listaram esse "tipo JOIN" separadamente, mas isso não faz sentido. É apenas uma forma de açúcar de sintaxe para o equi JOIN, que é um caso especial de Theta-JOIN ou INNER JOIN. NATURAL JOIN simplesmente coleta todas as colunas comuns às duas tabelas que estão sendo unidas e une USING()
essas colunas. O que quase nunca é útil, devido a correspondências acidentais (como LAST_UPDATE
colunas no banco de dados Sakila ).
Aqui está a sintaxe:
SELECT *
FROM actor
NATURAL JOIN film_actor
NATURAL JOIN film
Agora, OUTER JOIN
é um pouco diferente INNER JOIN
, pois cria um UNION
dos vários produtos cartesianos. Nós podemos escrever:
-- Convenient syntax:
SELECT *
FROM a LEFT JOIN b ON <predicate>
-- Cumbersome, equivalent syntax:
SELECT a.*, b.*
FROM a JOIN b ON <predicate>
UNION ALL
SELECT a.*, NULL, NULL, ..., NULL
FROM a
WHERE NOT EXISTS (
SELECT * FROM b WHERE <predicate>
)
Ninguém quer escrever o último, então escrevemos OUTER JOIN
(o que geralmente é melhor otimizado pelos bancos de dados).
Como INNER
, a palavra OUTER
- chave é opcional aqui.
OUTER JOIN
vem em três sabores:
LEFT [ OUTER ] JOIN
: A tabela esquerda da JOIN
expressão é adicionada à união, como mostrado acima.RIGHT [ OUTER ] JOIN
: A tabela direita da JOIN
expressão é adicionada à união, como mostrado acima.FULL [ OUTER ] JOIN
: As duas tabelas da JOIN
expressão são adicionadas à união, como mostrado acima.Tudo isso pode ser combinado com a palavra-chave USING()
ou com NATURAL
( na verdade, tive NATURAL FULL JOIN
recentemente um caso de uso do mundo real )
Existem algumas sintaxes obsoletas e históricas no Oracle e SQL Server, que OUTER JOIN
já eram suportadas antes do padrão SQL ter uma sintaxe para isso:
-- Oracle
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id = fa.actor_id(+)
AND fa.film_id = f.film_id(+)
-- SQL Server
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id *= fa.actor_id
AND fa.film_id *= f.film_id
Dito isto, não use esta sintaxe. Eu apenas listo isso aqui para que você possa reconhecê-lo em postagens antigas / código legado.
OUTER JOIN
Poucas pessoas sabem disso, mas o padrão SQL especifica particionado OUTER JOIN
(e a Oracle o implementa). Você pode escrever coisas assim:
WITH
-- Using CONNECT BY to generate all dates in January
days(day) AS (
SELECT DATE '2017-01-01' + LEVEL - 1
FROM dual
CONNECT BY LEVEL <= 31
),
-- Our departments
departments(department, created_at) AS (
SELECT 'Dept 1', DATE '2017-01-10' FROM dual UNION ALL
SELECT 'Dept 2', DATE '2017-01-11' FROM dual UNION ALL
SELECT 'Dept 3', DATE '2017-01-12' FROM dual UNION ALL
SELECT 'Dept 4', DATE '2017-04-01' FROM dual UNION ALL
SELECT 'Dept 5', DATE '2017-04-02' FROM dual
)
SELECT *
FROM days
LEFT JOIN departments
PARTITION BY (department) -- This is where the magic happens
ON day >= created_at
Partes do resultado:
+--------+------------+------------+
| day | department | created_at |
+--------+------------+------------+
| Jan 01 | Dept 1 | | -- Didn't match, but still get row
| Jan 02 | Dept 1 | | -- Didn't match, but still get row
| ... | Dept 1 | | -- Didn't match, but still get row
| Jan 09 | Dept 1 | | -- Didn't match, but still get row
| Jan 10 | Dept 1 | Jan 10 | -- Matches, so get join result
| Jan 11 | Dept 1 | Jan 10 | -- Matches, so get join result
| Jan 12 | Dept 1 | Jan 10 | -- Matches, so get join result
| ... | Dept 1 | Jan 10 | -- Matches, so get join result
| Jan 31 | Dept 1 | Jan 10 | -- Matches, so get join result
O ponto aqui é que todas as linhas do lado particionado da junção serão encerradas no resultado, independentemente se houver JOIN
alguma correspondência no "outro lado da junção". Longa história: é para preencher dados esparsos nos relatórios. Muito útil!
Seriamente? Nenhuma outra resposta conseguiu isso? Claro que não, porque infelizmente não possui uma sintaxe nativa no SQL (como ANTI JOIN abaixo). Mas podemos usar IN()
e EXISTS()
, por exemplo, encontrar todos os atores que atuaram nos filmes:
SELECT *
FROM actor a
WHERE EXISTS (
SELECT * FROM film_actor fa
WHERE a.actor_id = fa.actor_id
)
O WHERE a.actor_id = fa.actor_id
predicado atua como o predicado de semi-junção. Se você não acredita, consulte os planos de execução, por exemplo, no Oracle. Você verá que o banco de dados executa uma operação SEMI JOIN, não o EXISTS()
predicado.
Este é exatamente o oposto do SEMI JOIN ( ter cuidado para não usar NOT IN
embora , já que tem uma importante advertência)
Aqui estão todos os atores sem filmes:
SELECT *
FROM actor a
WHERE NOT EXISTS (
SELECT * FROM film_actor fa
WHERE a.actor_id = fa.actor_id
)
Algumas pessoas (especialmente as pessoas do MySQL) também escrevem ANTI JOIN assim:
SELECT *
FROM actor a
LEFT JOIN film_actor fa
USING (actor_id)
WHERE film_id IS NULL
Eu acho que a razão histórica é desempenho.
OMG, este é muito legal. Eu sou o único a mencionar isso? Aqui está uma consulta interessante:
SELECT a.first_name, a.last_name, f.*
FROM actor AS a
LEFT OUTER JOIN LATERAL (
SELECT f.title, SUM(amount) AS revenue
FROM film AS f
JOIN film_actor AS fa USING (film_id)
JOIN inventory AS i USING (film_id)
JOIN rental AS r USING (inventory_id)
JOIN payment AS p USING (rental_id)
WHERE fa.actor_id = a.actor_id -- JOIN predicate with the outer query!
GROUP BY f.film_id
ORDER BY revenue DESC
LIMIT 5
) AS f
ON true
Ele encontrará os 5 principais filmes produtores de receita por ator. Toda vez que você precisar de uma consulta TOP-N-por-algo, LATERAL JOIN
será seu amigo. Se você é uma pessoa do SQL Server, conhece esse JOIN
tipo com o nomeAPPLY
SELECT a.first_name, a.last_name, f.*
FROM actor AS a
OUTER APPLY (
SELECT f.title, SUM(amount) AS revenue
FROM film AS f
JOIN film_actor AS fa ON f.film_id = fa.film_id
JOIN inventory AS i ON f.film_id = i.film_id
JOIN rental AS r ON i.inventory_id = r.inventory_id
JOIN payment AS p ON r.rental_id = p.rental_id
WHERE fa.actor_id = a.actor_id -- JOIN predicate with the outer query!
GROUP BY f.film_id
ORDER BY revenue DESC
LIMIT 5
) AS f
OK, talvez isso seja trapaça, porque uma expressão LATERAL JOIN
ou APPLY
é realmente uma "subconsulta correlacionada" que produz várias linhas. Mas se permitirmos "subconsultas correlacionadas", também poderemos falar sobre ...
Isso é realmente implementado apenas pelo Oracle e Informix (que eu saiba), mas pode ser emulado no PostgreSQL usando matrizes e / ou XML e no SQL Server usando XML.
MULTISET
produz uma subconsulta correlacionada e aninha o conjunto de linhas resultante na consulta externa. A consulta abaixo seleciona todos os atores e, para cada ator, coleta seus filmes em uma coleção aninhada:
SELECT a.*, MULTISET (
SELECT f.*
FROM film AS f
JOIN film_actor AS fa USING (film_id)
WHERE a.actor_id = fa.actor_id
) AS films
FROM actor
Como você viu, existem mais tipos de Cadastre-se que apenas o "chato" INNER
, OUTER
e CROSS JOIN
que normalmente são mencionados. Mais detalhes no meu artigo . E, por favor, pare de usar os diagramas de Venn para ilustrá-los.
Vou empurrar minha irritação: a palavra-chave USING.
Se ambas as tabelas nos dois lados do JOIN tiverem suas chaves estrangeiras nomeadas corretamente (ou seja, mesmo nome, não apenas "id"), isso poderá ser usado:
SELECT ...
FROM customers JOIN orders USING (customer_id)
Acho isso muito prático, legível e não usado com frequência.