Como um LEFT OUTER JOIN pode retornar mais registros do que existem na tabela esquerda?


165

Eu tenho uma junção externa esquerda muito básica para retornar todos os resultados da tabela esquerda e algumas informações adicionais de uma tabela muito maior. A tabela da esquerda ainda contém 4935 registros. Quando eu deixei o JOIN em uma tabela adicional, a contagem de registros é significativamente maior.

Até onde eu sei, é um evangelho absoluto que um LEFT OUTER JOIN retornará todos os registros da tabela da esquerda com registros correspondentes da tabela da direita e valores nulos para qualquer linha que não possa ser correspondida; portanto, é meu entendimento que deve será impossível retornar mais linhas do que as existentes na tabela esquerda, mas isso está acontecendo da mesma forma!

A consulta SQL segue:

SELECT     SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID
FROM         SUSP.Susp_Visits LEFT OUTER JOIN
                      DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum

Talvez eu tenha cometido um erro na sintaxe ou meu entendimento de LEFT OUTER JOIN esteja incompleto, espero que alguém possa explicar como isso pode estar ocorrendo?

Postscript

Obrigado pelas ótimas respostas, meu entendimento de LEFT OUTER JOINS agora é muito melhor. Alguém poderia sugerir uma maneira de modificar essa consulta para que eu receba o máximo de registros retornados na tabela à esquerda?

Essa consulta é puramente para gerar um relatório e as correspondências duplicadas simplesmente confundem as coisas.

/ Postscript


5
Para "obter o máximo de registros retornados existentes na tabela esquerda", é necessário especificar qual linha do lado direito escolher se há várias correspondências.
AK

1
como você especifica isso? Gostaria que a primeira partida fosse devolvida.
Simon Cross

1
você precisa definir o que se entende pela primeira partida. Deseja o registro mais antigo, o de maior identificação ou o quê?
HLGEM

1
Se você coincidir com a chave primária na tabela adicional, sua declaração está correta.
Prageeth godage

Costumo usar um recurso como este como uma folha de dicas ao criar consultas. Se o link acabar, basta entrar no google sql join ; eles são diagramas de Venn dos diferentes tipos de junção.
Zimano 23/01

Respostas:


190

A ESQUERDA EXTERNA ESQUERDA retornará todos os registros da tabela ESQUERDA associados à tabela DIREITA sempre que possível.

Se houver correspondências, no entanto, ainda retornará todas as linhas correspondentes, portanto, uma linha na ESQUERDA que corresponda a duas linhas à DIREITA retornará como duas LINHAS, assim como um INNER JOIN.

EDIT: em resposta à sua edição, acabei de dar uma olhada na sua consulta e parece que você está retornando apenas dados da tabela ESQUERDA. Portanto, se você deseja apenas dados da tabela ESQUERDA e deseja apenas uma linha retornada para cada linha na tabela ESQUERDA, não é necessário executar uma JOIN e pode fazer um SELECT diretamente da tabela ESQUERDA.


1
O motivo de ingressar na tabela da direita foi o fato de eu só ter registros da esquerda onde havia pelo menos um registro na tabela da direita, mas muito obrigado pela explicação.
Jay Wilde

125
Table1                Table2
_______               _________
1                      2
2                      2
3                      5
4                      6

SELECT Table1.Id, Table2.Id FROM Table1 LEFT OUTER JOIN Table2 ON Table1.Id=Table2.Id

Resultados:

1,null
2,2
2,2
3,null
4,null

1
Tão simples e ao mesmo tempo tão poderoso.
kiradotee 11/06

39

Não é impossível. O número de registros na tabela esquerda é o número mínimo de registros que ele retornará. Se a tabela da direita tiver dois registros que correspondem a um registro na tabela esquerda, ela retornará dois registros.


12

Em resposta ao seu postscript, isso depende do que você gostaria.

Você está obtendo (possível) várias linhas para cada linha na tabela esquerda porque existem várias correspondências para a condição de associação. Se você deseja que o total de resultados tenha o mesmo número de linhas que existe na parte esquerda da consulta, verifique se as condições de junção causam uma correspondência 1 para 1.

Como alternativa, dependendo do que você realmente deseja, você pode usar funções agregadas (se, por exemplo, você quiser apenas uma string da parte direita, poderá gerar uma coluna que é uma string delimitada por vírgula dos resultados do lado direito da linha esquerda.

Se você estiver visualizando apenas 1 ou 2 colunas da junção externa, poderá considerar o uso de uma subconsulta escalar, pois você terá 1 resultado garantido.


4
Essa é uma boa resposta, pois ofereceu sugestões sobre como retornar apenas as linhas da tabela esquerda.
karns

9

Cada registro da tabela à esquerda será retornado quantas vezes houver registros correspondentes na tabela à direita - pelo menos 1, mas pode facilmente ser mais que 1.


8

ESQUERDO OUTER JOIN, assim como INNER JOIN (junção normal) retornará tantos resultados para cada linha na tabela esquerda quantas correspondências encontrar na tabela à direita. Portanto, você pode obter muitos resultados - até N x M, onde N é o número de linhas na tabela esquerda e M é o número de linhas na tabela direita.

É o número mínimo de resultados sempre garantido em LEFT OUTER JOIN para que seja pelo menos N.


1
Comecei a pensar quando o número de linhas é igual N x M e a única situação real que me vem à cabeça é quando N ou M é igual a 1. Você concorda?
precisa saber é o seguinte

2
Não eu não. Você não deve considerar a condição de junção apenas como junção de igualdade de chave. Pode ser uma condição arbitrária, por exemplo, intervalos de datas, desigualdades, etc. Dois casos extremos: (a) N linhas não têm uma única correspondência entre as linhas M, e a junção externa deixada resulta em N linhas correspondentes a NULLs. (b) cada uma das N linhas corresponde a todas as M linhas, então o resultado é N x M linhas definidas.
topchef 26/09/13

1
Você está certo, eu estava pensando em uniões apenas em termos de igualdade de chave. Eu gosto do seu exemplo do "caso b". Acredito que "todas as N linhas correspondem a todas as M linhas" é uma receita geral para quando N x M linhas são retornadas, o que é bastante impossível de visualizar quando se pensa apenas na igualdade de chaves.
precisa saber é o seguinte

7

Poderia ser uma relação de um para muitos entre as tabelas esquerda e direita?


6

Preste atenção se você tiver uma cláusula where na tabela "lado direito" de uma consulta que contenha uma junção externa esquerda ... Caso você não tenha nenhum registro no lado direito que satisfaça a cláusula where, o registro correspondente do lado esquerdo 'tabela não aparecerá no resultado da sua consulta ....


1
Você deve então adicionar a condição à cláusula ON do LETER OUTER JOIN correspondente correspondente.
Mik

6

Se você precisar de apenas uma linha do lado direito

SELECT SuspReason, SiteID FROM(
    SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID, ROW_NUMBER()
    OVER(PARTITION BY SUSP.Susp_Visits.SiteID) AS rn
    FROM SUSP.Susp_Visits
    LEFT OUTER JOIN DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum
) AS t
WHERE rn=1

ou apenas

SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID
FROM SUSP.Susp_Visits WHERE EXISTS(
    SELECT DATA.Dim_Member WHERE SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum
)

1
Como você não forneceu DDL e DML, eu não testei. Enfim, eu acho que EXISTE é o que você quer. Tente isso: SELECT SuspReason, SiteID FROM (SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID, ROW_NUMBER () OVER (PARTITION BY SUSP.Susp_Visits.SiteID ORDER BY SUSP.Susp_Visits.SiteID) AS rn FROM SUSP.Susp_Visits.SiteID JOIN DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum) AS t WHERE rn = 1
AK

2

Parece que existem várias linhas na tabela DATA.Dim_Member por linha SUSP.Susp_Visits.


2

se várias (x) linhas em Dim_Member estiverem associadas a uma única linha em Susp_Visits, haverá x linhas no conjunto de resultados.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.