Wednesday, February 24, 2010

Oracle SQL - Usando LEFT and RIGHT JOIN

Olá,

Hoje o assunto é OUTER JOIN.
Essa dica de post eu peguei com o meu amigo Eduardo do blog bieduardo.blogspot.com/ .

Normalmente muitos profissionais caem nesta dúvida cruel.
Como fazer corretamente um OUTER JOIN?

Pirmeiro vamos relembrar o que é um OUTER JOIN.
"Um OUTER JOIN é um SIMPLE JOIN ou INNER JOIN  com uma "opção extendida " de trazer também os dados que não satisfazem a condição de JOIN.

No Oracle para usar LEFT ou RIGHT  OUTER JOIN em seu SQL você pode usar o caracter "+" entre parênteses para informar ao Oracle qual operador você está utilizando.Você também pode usar o padrão SQL92 para JOIN usando as palavras RIGHT OUTER JOIN e LEFT OUTER JOIN.

Mostrarei isso mais a frente no segundo post.

A explicação sobre de qual lado utilizar é simples:

Se a coluna que contém os dados nulos é a da direita você então coloca o sinal (+) na coluna da esquerda e vice-versa.

Ex. Nas tabelas A e B existe a  coluna ID do tipo NUMBER.
Na tabela A existe uma linha em que a coluna ID é nula,mas mesmo assim você precisa trazer esta linha na sua query ,neste caso você precisar fazer um JOIN para obtê - las.

ex.

select 
from tabela1 A,tabela2 B
where A.id = B.id(+) ;

No exemplo acima foi feito um LEFT JOIN pois quero retornar todos os dados da tabela A que não satisfazem a condição da JOIN .

Criando as tabelas de exemplo :

dbajcc@DBPOST on 23-FEB-10 >create table jcc_join_a
(seq number(2) ,
 text varchar2(10)) ;  2    3

Table created.

Elapsed: 00:00:00.03
dbajcc@DBPOST on 23-FEB-10 > insert into jcc_join_a
 values(1,'disk1') ;  2

1 row created.

Elapsed: 00:00:00.02
dbajcc@DBPOST on 23-FEB-10 > insert into jcc_join_a
 values(2,'disk2') ;  2

1 row created.

Elapsed: 00:00:00.00
dbajcc@DBPOST on 23-FEB-10 > insert into jcc_join_a(seq)
 values(3) ;  2

1 row created.

Elapsed: 00:00:00.00
dbajcc@DBPOST on 23-FEB-10 >commit ;

Commit complete.

Elapsed: 00:00:00.00
dbajcc@DBPOST on 23-FEB-10 > create table jcc_join_b
(seq number(2) ,
 text varchar2(10)) ;  2    3

Table created.

Elapsed: 00:00:00.02
dbajcc@DBPOST on 23-FEB-10 > insert into jcc_join_b
 values(1,'disk1') ;
   2
1 row created.

Elapsed: 00:00:00.01
dbajcc@DBPOST on 23-FEB-10 >  insert into jcc_join_b
 values(2,'disk2') ;  2

1 row created.

Elapsed: 00:00:00.00
dbajcc@DBPOST on 23-FEB-10 > insert into jcc_join_b(text)
 values('disk3') ;  2

1 row created.

Elapsed: 00:00:00.00
dbajcc@DBPOST on 23-FEB-10 >

Fazendo um RIGHT JOIN :

dbajcc@DBPOST on 23-FEB-10 >select a.* ,b.*
 from jcc_join_a a,
      jcc_join_b b
where a.seq(+) = b.seq ;  2    3    4

       SEQ TEXT              SEQ TEXT
---------- ---------- ---------- ----------
         1 disk1               1 disk1
         2 disk2               2 disk2
                                 disk3

Elapsed: 00:00:00.02
dbajcc@DBPOST on 23-FEB-10 >

Ou usando a sintaxe do padrão SQL92 :

dbajcc@DBPOST on 24-FEB-10 >select  a.* ,b.*
  2  from jcc_join_a a right outer join jcc_join_b b
  3   on  a.seq = b.seq ;

       SEQ TEXT              SEQ TEXT
---------- ---------- ---------- ----------
         1 disk1               1 disk1
         2 disk2               2 disk2
                                 disk3

Elapsed: 00:00:00.00
dbajcc@DBPOST on 24-FEB-10 >


Acima destaquei em azul a coluna na qual é o alvo e que por sinal contém um campo SEQ nulo para o campo TEXT "disk3" .

Agora vamos fazer um LEFT JOIN :


[oracle@marte ~]$ sqlplus dbajcc

SQL*Plus: Release 11.2.0.1.0 Production on Wed Feb 24 07:49:02 2010

Copyright (c) 1982, 2009, Oracle.  All rights reserved.

Enter password:

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, Automatic Storage Management, OLAP, Data Mining
and Real Application Testing options

dbajcc@DBPOST on 24-FEB-10 > select a.* ,b.*
 from jcc_join_a a,
      jcc_join_b b
where a.seq = b.seq(+) ;  2    3    4

       SEQ TEXT              SEQ TEXT
---------- ---------- ---------- ----------
         1 disk1               1 disk1
         2 disk2               2 disk2
         3

Elapsed: 00:00:00.05
dbajcc@DBPOST on 24-FEB-10 >

Ou usando o outro tipo de sintaxe :

dbajcc@DBPOST on 24-FEB-10 >select  a.* ,b.*
  2  from jcc_join_a a left outer join jcc_join_b b
  3  on  a.seq = b.seq ;

       SEQ TEXT              SEQ TEXT
---------- ---------- ---------- ----------
         1 disk1               1 disk1
         2 disk2               2 disk2
         3

Elapsed: 00:00:00.19
dbajcc@DBPOST on 24-FEB-10 >


Temos uma outra opção que é usar a um FULL OUTER JOIN para trazer os dados que não satisfazem a condição de JOIN das duas tabelas envolvidas.

dbajcc@DBPOST on 24-FEB-10 >select  a.* ,b.*
  2  from jcc_join_a a full outer join jcc_join_b b
  3   on  a.seq = b.seq ;

       SEQ TEXT              SEQ TEXT
---------- ---------- ---------- ----------
         1 disk1               1 disk1
         2 disk2               2 disk2
                                 disk3
         3

Elapsed: 00:00:00.01
dbajcc@DBPOST on 24-FEB-10 >



Nem vou trazer exemplos sobre Cartesian Join pois acredito ser de pouca utilidade.

Até,

Júlio César Corrêa 

2 comments:

Eduardo Legatti said...

Olá Júlio,

Excelente post. Aliás, seu blog está ótimo!

Abraços,

Eduardo Legatti

Unknown said...

Olá Eduardo,

Muito obrigado por passar por aqui!
Vamos aprendendo dia após dia.
Ainda tenho muito que apreder a postar artigos com vocês mestres!