none
Diferença entre Left Join e *= (Resultados diferentes) RRS feed

  • Pergunta

  • Pessoal boa tarde.

    Me deparei um com um problema:

    Tenho duas querys uma com *=, e outra com Left Join.

    As duas são identifcas, mas retornam um numero diferente de registros:

    Observem:

    SELECT COUNT(1)
     FROM DBO.TRANS   A , 
       DBO.P_EMPRESA B ,
       DBO.EMPRESA  E   
     WHERE   A.ID_TRANS *= B.ID_TRANS 
       AND E.ID_EMP  *= B.ID_EMP  

    --TOTAL DE REGISTROS: 244953

    SELECT COUNT(1)
     FROM DBO.TRANS   A
       LEFT JOIN  DBO.P_EMPRESA B
       ON  A.ID_TRANS = B.ID_TRANS
       LEFT JOIN DBO.EMP  E  
       ON E.ID_EMP  = B.ID_EMP 

    --TOTAL DE REGISTROS: 51927

    Alguem pode me explicar o porque que isso acontece?

    Desde já agradeço!


    Coordenador de Projetos / DBA
    quinta-feira, 7 de outubro de 2010 17:33

Respostas

  • Ale2009

    da uma olhada no Blog do Maia.. ele tem um artigo muito interessanet sobre o assunto

    <cite>gustavomaiaaguiar.spaces.live.com</cite>

    Att.
    Marcelo Fernandes 


    Não Perca o Worldwide Online TechDay 2010

    Um evento gratuito com grandes personalidades (Buck Woody, Chad Miller, Steve Jones, Fabricio Catae e muito mais...

    Eu vou falar sobre particionamento de tabelas registre-se

    Acesse o site do evento http://www.online.techday.net.br

    MCP, MCDBA, MCSA, MCTS.
    Se útil, classifique!!!
    Me siga no twitter: @marcelodba

    sexta-feira, 8 de outubro de 2010 14:04

Todas as Respostas

  • Olá, analisando os seus selects ele realmete irá retornar quantidades diferentes.

    No primeiro select quando é colocado AND E.ID_EMP  *= B.ID_EMP  o retorno será tudo que existe na tabela DBO.EMPRESA , mesmo que não exista nas outras tabelas.

    Já no segundo select  LEFT JOIN DBO.EMP  E  ON E.ID_EMP  = B.ID_EMP o retorno será tudo que exista nas outras tabelas mesmo que não exista na DBO.EMPRESA.

    Não sei se consegui ser claro, então vamos pros exemplos:

    Caso queira que os selects retorne as mesmas quantidades vai o script abaixo:

     

     

    SELECT COUNT(1)
     FROM DBO.TRANS   A ,  
       DBO.P_EMPRESA B ,
       DBO.EMPRESA  E   
     WHERE   A.ID_TRANS *= B.ID_TRANS  
       AND E.ID_EMP  *= B.ID_EMP  

    --TOTAL DE REGISTROS: 244953

    SELECT COUNT(1)
     FROM DBO.TRANS   A
       LEFT JOIN  DBO.P_EMPRESA B 
       ON  A.ID_TRANS = B.ID_TRANS 
       right JOIN DBO.EMP  E  
       ON E.ID_EMP  = B.ID_EMP 

    --TOTAL DE REGISTROS: 244953

     

     

    OU

     

    SELECT COUNT(1)
     FROM DBO.TRANS   A ,  
       DBO.P_EMPRESA B ,
       DBO.EMPRESA  E   
     WHERE   A.ID_TRANS *= B.ID_TRANS  
       AND E.ID_EMP  =* B.ID_EMP  

    --TOTAL DE REGISTROS: 51927

    SELECT COUNT(1)

     FROM DBO.TRANS   A
       LEFT JOIN  DBO.P_EMPRESA B 
       ON  A.ID_TRANS = B.ID_TRANS 
       LEFT JOIN DBO.EMP  E  
       ON E.ID_EMP  = B.ID_EMP 

    --TOTAL DE REGISTROS: 51927

     

    sexta-feira, 8 de outubro de 2010 00:05
  • Olá, primeiramente, muito obrigado por sua resposta.

    Executei seus scripts e os resultados que obtive, ainda são diferentes.

    Observe:

    SELECT COUNT(1)
     FROM DBO.TRANS   A ,  
       DBO.P_EMPRESA B ,
       DBO.EMPRESA  E   
     WHERE   A.ID_TRANS *= B.ID_TRANS  
       AND E.ID_EMP  *= B.ID_EMP  

    --TOTAL DE REGISTROS: 244953

    SELECT COUNT(1)
     FROM DBO.TRANS   A
       LEFT JOIN  DBO.P_EMPRESA B 
       ON  A.ID_TRANS = B.ID_TRANS 
       right JOIN DBO.EMP  E  
       ON E.ID_EMP  = B.ID_EMP 

    --TOTAL DE REGISTROS: 24505

     

    observe que existem muito menos registros quando executo o right join...

    Qual pode ser o problema? registros Nulos ??

    Obrigado mais uma vez!

     


    Coordenador de Projetos / DBA
    sexta-feira, 8 de outubro de 2010 13:48
  • Ale2009

    da uma olhada no Blog do Maia.. ele tem um artigo muito interessanet sobre o assunto

    <cite>gustavomaiaaguiar.spaces.live.com</cite>

    Att.
    Marcelo Fernandes 


    Não Perca o Worldwide Online TechDay 2010

    Um evento gratuito com grandes personalidades (Buck Woody, Chad Miller, Steve Jones, Fabricio Catae e muito mais...

    Eu vou falar sobre particionamento de tabelas registre-se

    Acesse o site do evento http://www.online.techday.net.br

    MCP, MCDBA, MCSA, MCTS.
    Se útil, classifique!!!
    Me siga no twitter: @marcelodba

    sexta-feira, 8 de outubro de 2010 14:04
  • Olá Marcelo, obrigado pela resposta.

    Entendi o o Gustavo Maia explicou, sei que deve ser o mesmo principio do problema, mas nao estou conseguindo visualizar a resposta do meu problema, pode me dar uma mao?

     

    Obrigado.


    Coordenador de Projetos / DBA
    sexta-feira, 8 de outubro de 2010 15:01
  • Ale2009

    Probleminha legal este seu :-)

    Seguinte.. consegui simular o seu problema... e acredito que o seu problema é justamente o que o Gustavo descreve no artigo http://gustavomaiaaguiar.spaces.live.com/blog/cns!F4F5C630410B9865!422.entry, execute o script abaixo e rode os dois selects exibindo o excution plan... preste atenção na diferença entre o plano das duas consultas...

    observe que no left join ele faz primeiro um "left join" da tbMateria com a tbAluno e faz um "left join" deste resultado com a tbProfessor.
    E no *= o SQL faz um "INNER JOIN" da tbProfessor com a tbMateria e exibe um warning que não tem join predicate, neste ponto ele faz um "CROSS" da tbProfessor com a tbAluno e pega este resultado e faz um "left Join" com tbAluno

    Espero ter sido claro... mas se você olhar o plano de execução poderá ver isto ocorrendo :D

    CREATE TABLE tbMateria (
     idMateria INT NOT NULL IDENTITY(1,1),
     dsMateria VARCHAR(20) NOT NULL)
    Alter table tbMateria add CONSTRAINT PK_Materia PRIMARY KEY (idMateria) 
    go
    
    CREATE TABLE tbProfessor (
     idProfessor INT NOT NULL IDENTITY(1,1),
     dsNomePof VARCHAR(20) NOT NULL )
    Alter table tbProfessor add CONSTRAINT PK_Professor PRIMARY KEY (idProfessor) 
     
    go
    CREATE TABLE tbAluno (
     idAluno INT NOT NULL IDENTITY(1,1),
     dsNome VARCHAR(20) NOT NULL,
     idMateria INT NOT NULL,
     idProfessor INT NOT NULL,
     nrSerie tinyint NOT NULL )
    alter table tbAluno add CONSTRAINT PK_Aluno PRIMARY KEY (idAluno)
    alter table tbAluno add CONSTRAINT FK_Materia_aluno FOREIGN KEY (idMateria) REFERENCES tbMateria (idMateria)
    alter table tbAluno add CONSTRAINT FK_Professor_aluno FOREIGN KEY (idProfessor) REFERENCES tbProfessor (idProfessor)
    go
    -- alimentando tbMateria
    INSERT INTO tbMateria (dsMateria) VALUES ('Matemática')
    INSERT INTO tbMateria (dsMateria) VALUES ('Português')
    INSERT INTO tbMateria (dsMateria) VALUES ('Biologia')
    INSERT INTO tbMateria (dsMateria) VALUES ('Química')
    INSERT INTO tbMateria (dsMateria) VALUES ('Geografia') 
    go
    
    
    -- alimentando tbProfessor
    INSERT INTO tbProfessor (dsNomePof) VALUES ('Yoda')
    INSERT INTO tbProfessor (dsNomePof) VALUES ('Obi-Wan')
    
    go
    -- alimentando tbAluno
    INSERT INTO tbAluno (dsNome,idMateria,idProfessor,nrSerie) VALUES ('Leia',1,1,1) 
    INSERT INTO tbAluno (dsNome,idMateria,idProfessor,nrSerie) VALUES ('C3PO',2,1,2) 
    INSERT INTO tbAluno (dsNome,idMateria,idProfessor,nrSerie) VALUES ('R2D2',3,2,3) 
    INSERT INTO tbAluno (dsNome,idMateria,idProfessor,nrSerie) VALUES ('VADER',2,2,3) 
    INSERT INTO tbAluno (dsNome,idMateria,idProfessor,nrSerie) VALUES ('Padme',1,2,1) 
    
    --teste 1
    SELECT
     dsNome, nrSerie, dsMateria,dsNomePof
    FROM
     tbMateria AS mat
     LEFT OUTER JOIN tbAluno AS alu ON mat.idMateria = alu.idMateria 
     left OUTER JOIN tbProfessor AS prof ON prof.idProfessor = alu.idProfessor
    
    --teste 2
    SELECT
     dsNome, nrSerie, dsMateria,dsNomePof
    FROM
     tbAluno AS alu, tbMateria AS mat, tbProfessor AS prof
    WHERE
     mat.idMateria *= alu.idMateria 
     and prof.idProfessor *= alu.idProfessor
    
    go
    drop table tbAluno
    drop table tbMateria
    drop table tbProfessor
    

    att.
    Marcelo Fernandes


    Não Perca o Worldwide Online TechDay 2010

     

    Um evento gratuito com grandes personalidades (Buck Woody, Chad Miller, Steve Jones, Fabricio Catae e muito mais...

    Eu vou falar sobre particionamento de tabelas registre-se

    Acesse o site do evento http://www.online.techday.net.br

    MCP, MCDBA, MCSA, MCTS.
    Se útil, classifique!!!
    Me siga no twitter: @marcelodba

    sexta-feira, 8 de outubro de 2010 22:26
  • Marcelo, novamente obrigado pela explicação.

    Entendi o problema e consegui resolver.

    Grande abraço!


    Coordenador de Projetos / DBA
    segunda-feira, 11 de outubro de 2010 18:08