Usuário com melhor resposta
Diferença entre Left Join e *= (Resultados diferentes)

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
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- Marcado como Resposta Alessandro Falanque sexta-feira, 8 de outubro de 2010 14:45
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
-
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 -
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- Marcado como Resposta Alessandro Falanque sexta-feira, 8 de outubro de 2010 14:45
-
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 -
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 tbAlunoEspero 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 2010Eu 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 -