Join é a ferramenta básica de trabalho nos bancos de dados relacionais. É através dos diferentes tipos de join que conseguimos recuperar dados de uma ou mais tabelas com o auxílio dos relacionamentos existentes.

Nessa matéria discutiremos os 4 modelos de join (inner join, left join, right join e full outer join);  aprenderemos também como escolher o tipo certo de join para cada situação.

Para os exemplos a seguir serão consideradas duas tabelas : produto e venda. A tabela venda - como o prórpio nome sugere - irá registrar vendas de itens cadastrados na tabela produto, mas pela característica do negócio também serão permitidas vendas de produtos sem cadastro.

O script abaixo irá criar e popular as tabelas venda e produto:


/* criação da tabela produto */
create table produto
(
	cod_produto int primary key,
	descr_produto varchar (20)
)
/* criação da tabela venda.*/
create table venda
( 
	id_venda int identity primary key,
	cod_produto int ,
	qtde int,
	vlr_unit dec(9,2)
)
/* populando a tabela produto */
insert into produto values (101001,'Livro-1')
insert into produto values (101002,'Livro-2')
insert into produto values (101003,'Livro-3')
insert into produto values (101004,'Livro-4')
insert into produto values (101005,'Livro-5')
/* populando a tabela venda */
insert into venda (cod_produto,qtde,vlr_unit)  values (101001,2,14.00)
insert into venda (cod_produto,qtde,vlr_unit)  values (101002,1,20.50)
insert into venda (cod_produto,qtde,vlr_unit)  values (101003,4,12.00)
insert into venda (cod_produto,qtde,vlr_unit)  values (101030,6, 8.00)
insert into venda (cod_produto,qtde,vlr_unit)  values (101031,1,44.00)

O relacionamento entre as tabelas produto e venda pode ser visualizado na Figura 1.

Relacionamento entre as tabelas produto e venda
Figura 1. Relacionamento entre as tabelas produto e venda
cadastrados (tab.produto) vendidos (tab.venda) vendidos sem cadastro cadastrados e não vendidos
vermelho + verde verde + azul azul vermelho
10101 10101
10102 10102
10103 10103
10104 10104
10105 10105
10130 10130
10131 10131
 

Observemos o seguinte:

A área em vermelho representa os produtos que foram cadastrados mas não foram vendidos.Para resgatar esses produtos devemos utilizar um left join , ligando um filtro para listar SOMENTE as linhas EXISTENTES na tabela produto SEM CORRESPONDÊNCIA na tabela venda;

A área em azul representa produtos que foram vendidos e não possuem cadastro. Para resgatar esses produtos deveremos utilizar um right join ligando um filtro para listar SOMENTE as linhas EXISTENTES na tabela venda SEM CORRESPONDÊNCIA na tabela produto ;

A área em verde representa a intersecção dos dois conjuntos, isto é, produtos que foram vendidos e possuem cadastro. Para selecionar as linhas que possuem equivalência nas duas tabelas utilizamos o inner join ;

Para representar a união de todos os produtos com todas as vendas, independentemente de relacionamento (áreas em vermelho+verde+azul) utilizamos um full outer join.

Vamos agora praticar a execução diferentes tipos de join para responder as questões a seguir:

Listar os produtos que foram vendidos e possuem cadastro

A resposta está na interseção entre produto e venda, representado na Figura 1 pela cor verde . Será resolvido com um inner join :


select produtos_vendidos_com_cadastro = p.cod_produto 
from produto p 
inner join 
    venda v 
on p.cod_produto = v.cod_produto 
-----------------------------------------------------
produtos_vendidos_com_cadastro 
----------------------------------------------------- 
101001 
101002 
101003 
(3 row(s) affected)

Listar os produtos que foram vendidos sem cadastro

Deveremos resgatar os produtos da área em azul , que não possuem correspondência na tabela produto . Será utilizado um right join para selecionar todas as linhas da tabela venda ;  o filtro .... ... where p.cod_ produto is null nos permitirá filtrar somente as vendas de produtos sem cadastro:


select produtos_vendidos_sem_cadastro = v.cod_produto
from produto p 
right outer join 
      venda v 
on v.cod_produto = p.cod_produto 
where p.cod_ produto IS NULL 
-----------------------------------------------------
produtos_vendidos_sem_cadastro 
----------------------------------------------------- 
101030 
101031 
(2 row(s) affected)

Listar os produto com cadastro que NÃO foram vendidos

A resposta para essa pergunta está na área em vermelho da figura-1. Para sua resolução foi empregado um left join , mas o mesmo resultado poderia ser obtido com um right join , bastando para isso inverter a ordem das tabelas   ... from venda v right outer join  produto p on ....


select produtos_com_cadastro_sem_venda = p.cod_produto
from produto p
left outer join
      venda v
on v.cod_produto = p.cod_produto
where v.cod_produto IS NULL
produtos_com_cadastro_sem_venda 
------------------------------------------------------
101004
101005
(2 row(s) affected)

Algumas dicas interessantes:

 

Left Join irá listar todas as linhas da primeira tabela relacionada no join, logo após a cláusula from.

Right Join irá listar todas as linhas referentes à segunda tabela relacionada no join ;

Em ambos os casos , quando a linha listada não possuir equivalência na tabela destino , as colunas da tabela destino   aparecerão com valores nulos

Formule um join para responder às questões abaixo

  • Quais foram os produtos vendidos que possuíam cadastro ; 
  • Quais foram os produtos vendidos que não possuíam cadastro ; 
  • Quais foram os produtos com cadastro que não foram vendidos

Além do código do produto, liste também sua descrição ( produtos sem cadastro deverão aparecer com a descrição “ sem cadastro ”) e, numa coluna de nome observação , informe uma das três possibilidades: venda com cadastro (= item a),  venda sem cadastro (= item b) ou produto com cadastro sem venda (= item c).


select produto = case when p.cod_ produto is nul
then v.cod_ produto
	 else p.cod_ produto
	end, 
	descricao = case when p.descr_ produto is NOT null 
	then p.descr_produto 
	else 'sem cadastro' 
end, 
observacao = case when p.cod_ produto is NOT null  and v.cod_ produto is NOT null
then 'venda com cadastro' 
 when p.cod_ produto    
 is NOT null  and v.cod_ produto
 is  null 
   then 'produto com cadastro sem venda' 
 else 'produto sem cadastro com venda'
end
from produto p 
full outer join 
     venda v 
on p.cod_ produto = v.cod_ produto 
---------------------------------------------------------------------------------
produto     descricao                      observacao                  
---------------------------------------------------------------------------------
101001      Livro-1                        venda com cadastro 
101002      Livro-2                        venda com cadastro 
101003      Livro-3                        venda com cadastro 
101004      Livro-4                        produto com cadastro sem venda 
101005      Livro-5                        produto com cadastro sem venda 
101030      sem cadastro                   produto sem cadastro com venda 
101031      sem cadastro                   produto sem cadastro com venda 
(7 row(s) affected)
    

E o CROSS JOIN ?

O cross join irá relacionar todos os elementos da primeira tabela com todos os elementos da segunda tabela; num movimento conhecido por Produto Cartesiano. Pode ser que você nunca precise utilizar esse tipo de join, mas é bom saber que existe e em que situações poderia ser utilizado.

Vamos supor que você possua uma tabela com siglas das unidades da federação. Você quer emitir uma listagem onde os produtos apareçam ao lado de cada sigla da federação. A tabela de unidades da federação e o select para produzir o relatório encontram-se listados a seguir.


/* criação da tabela uf */ 
create table uf ( sigla char(2)) 
insert into uf values ('SP') 
insert into uf values ('RJ') 

/* select com o Produto Cartesiano entre a tabela produto e uf */ 
select * 
from produto 
cross join uf 
------------------------------------------------------------
------------------------------------------------------------ 
cod_produto             descr_produto      sigla 
-----------------      --------------------      ------ 
101001                      Livro-1                  SP 
101002                      Livro-2                  SP 
101003                      Livro-3                  SP 
101004                      Livro-4                  SP 
101005                      Livro-5                  SP 
101001                      Livro-1                  RJ 
101002                      Livro-2                  RJ 
101003                      Livro-3                  RJ 
101004                      Livro-4                  RJ 
101005                      Livro-5                  RJ 
(10 row(s) affected)

Conclusão

Antes de escolher o tipo de join para sua query, visualize o que realmente você deseja. Conhecer os tipos de join existentes para utilizá-los quando a situação exige pode ser a diferença entre o certo e o errado, o rápido e o lento.