0Pricing
Coding Interview Prep · Aula

Expansão de junções e multiplicação de linhas

Entenda por que uma junção pode retornar mais linhas do que qualquer uma das tabelas e como entrevistadores testam isso.

Expansão de junções e multiplicação de linhas é uma aula grátis de Coding Interview Prep no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Coding Interview Prep, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Coding Interview Prep inclui 4 aulas no total.

Quando um JOIN retorna linhas demais

Uma das perguntas de entrevista mais reveladoras parece inocente: "uma junção pode retornar mais linhas do que a tabela maior?" A resposta é sim, e o fenômeno é chamado de expansão ou multiplicação de linhas.

Candidatos que dizem "uma junção apenas combina tabelas" não percebem isso. Candidatos que conseguem prever a quantidade exata de linhas são contratados. Esta lição desenvolve essa capacidade de previsão.

A causa: correspondências um-para-muitos

A expansão acontece quando uma linha à esquerda corresponde a várias linhas à direita. Cada correspondência produz uma linha de saída separada.

Com clientes e pedidos, Ada (uma cliente) tem dois pedidos. A junção gera uma linha por pedido, portanto Ada aparece duplicada. Os campos do cliente se repetem; apenas os campos do pedido diferem.

SELECT c.name, o.amount
FROM customers c
JOIN orders o ON o.customer_id = c.id;
-- Ada appears twice (she has 2 orders)
-- name | amount
-- Ada  | 50
-- Ada  | 20
-- Bob  | 99

Contando as linhas de saída

A quantidade de linhas de saída é igual à soma das correspondências por linha da esquerda, não à quantidade de clientes.

  • Ada -> 2 pedidos -> 2 linhas
  • Bob -> 1 pedido -> 1 linha
  • Cleo -> 0 pedidos -> 0 linhas (removida pelo INNER JOIN)

Total = 3 linhas, embora a tabela de clientes também tenha 3 linhas. Se Ada passar a ter 10 pedidos, o resultado saltará para 11 linhas.

Muitos-para-muitos explode

A expansão se intensifica quando os dois lados têm várias correspondências para a mesma chave. Se a chave K aparece 3 vezes à esquerda e 4 vezes à direita, a junção produz 3 x 4 = 12 linhas para essa chave.

É assim que uma junção aparentemente pequena cresce para milhões de linhas. Os entrevistadores adoram fornecer chaves duplicadas nos dois lados para verificar se você percebe a multiplicação.

-- left has 3 rows with tag 'A', right has 4 rows with tag 'A'
SELECT l.id, r.id
FROM left_t l
JOIN right_t r ON r.tag = l.tag;
-- tag 'A' alone yields 3 * 4 = 12 output rows

A armadilha da agregação

Este é o erro que os entrevistadores mais costumam preparar. Você faz uma junção entre pedidos e itens do pedido para obter os detalhes dos itens e depois calcula o SUM do valor do pedido. Como cada pedido se expande em várias linhas de itens, o valor do pedido é contado uma vez por item.

O SUM fica muito inflado. A consulta parece correta e até é executada, o que a torna perigosa.

-- BUG: order.amount duplicated across items
SELECT SUM(o.amount) AS total
FROM orders o
JOIN order_items i ON i.order_id = o.id;
-- a 3-item order counts o.amount 3 times

Observando a inflação

Suponha que um pedido tenha valor 100 e três itens. A junção produz três linhas, cada uma carregando o valor 100. SUM(o.amount) retorna 300, não 100.

A solução é agregar na granularidade correta: some os itens ou some os pedidos distintos separadamente. Nunca calcule o SUM de um valor do registro pai sobre uma junção expandida com registros filhos.

o.id | o.amount | i.id
7    | 100      | 71
7    | 100      | 72
7    | 100      | 73
-- SUM(o.amount) = 300  (WRONG, should be 100)

Correção 1: agregue primeiro os filhos

A correção mais limpa é pré-agregar o lado com muitos registros em uma subconsulta ou CTE, para que cada registro pai corresponda exatamente a uma linha resumida. Sem expansão, sem inflação.

Aqui, reduzimos os itens a uma linha por pedido antes da junção, portanto o valor do registro pai nunca é duplicado.

SELECT o.id, o.amount, i.item_count
FROM orders o
JOIN (
  SELECT order_id, COUNT(*) AS item_count
  FROM order_items
  GROUP BY order_id
) i ON i.order_id = o.id;

Correção 2: COUNT(DISTINCT) e somas condicionais

Se precisar agregar depois de uma junção expandida, conte ou some na granularidade correta. Use COUNT(DISTINCT o.id) para contar pedidos em vez de linhas de itens.

Observação: SUM(DISTINCT o.amount) NÃO é uma correção segura, porque dois pedidos diferentes podem legitimamente ter o mesmo valor e seriam combinados. A pré-agregação é mais confiável.

SELECT COUNT(DISTINCT o.id)   AS num_orders,
       COUNT(i.id)            AS num_items
FROM orders o
JOIN order_items i ON i.order_id = o.id;

Detectando a expansão antes que cause problemas

Um diagnóstico rápido de que os entrevistadores gostam: verifique se a chave da junção é única no lado que você espera que seja o "um". Se a quantidade de chaves distintas for menor que a quantidade de linhas, esse lado tem duplicatas e causará expansão.

-- if this returns rows, order_id is NOT unique in order_items
SELECT order_id, COUNT(*) AS n
FROM order_items
GROUP BY order_id
HAVING COUNT(*) > 1;

Verificando sua granularidade com uma contagem

Antes de confiar em qualquer agregação sobre um resultado combinado, verifique a quantidade de linhas. Um truque rápido é comparar a contagem da junção com a contagem da tabela que você espera que defina a granularidade.

Se COUNT(*) sobre a junção for maior que COUNT(*) de pedidos, a junção se expandiu e qualquer agregação por pedido está em risco. Esta verificação de uma linha já salvou muitas respostas em entrevistas.

-- joined rows should equal order count if no fan-out
SELECT COUNT(*) AS joined_rows
FROM orders o
JOIN order_items i ON i.order_id = o.id;

SELECT COUNT(*) AS order_rows FROM orders;
-- joined_rows > order_rows  =>  fan-out present

A expansão nem sempre é um erro

Às vezes, você quer uma linha por filho. Listar cada item do pedido com o cabeçalho do pedido é uma expansão correta. A habilidade está em conhecer sua granularidade: quantas linhas uma entidade deve produzir?

Declare a granularidade antes de escrever a consulta. "Quero uma linha por item do pedido" em comparação com "uma linha por pedido" determina se a expansão é um recurso ou um erro.

Verificação rápida

Preveja a saída de uma junção um-para-muitos.

Recapitulação: expansão e multiplicação de linhas

O que você deve lembrar:

  • Um JOIN gera uma linha por par correspondente, portanto as correspondências um-para-muitos duplicam o lado "um".
  • Chaves muitos-para-muitos se multiplicam: 3 x 4 = 12 linhas para essa chave.
  • Agregar um valor do registro pai sobre uma junção expandida infla somas e contagens.
  • Corrija isso pré-agregando os filhos ou contando/somando na granularidade correta (por exemplo, COUNT(DISTINCT)).
  • Sempre declare primeiro a granularidade desejada; a expansão só é um erro quando a viola.

Perguntas Frequentes

A aula “Expansão de junções e multiplicação de linhas” é grátis?

Sim — o texto completo de “Expansão de junções e multiplicação de linhas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Coding Interview Prep, atualize para CoddyKit PRO. O curso de Coding Interview Prep inclui 4 aulas no total.

O que vou aprender em “Expansão de junções e multiplicação de linhas”?

Entenda por que uma junção pode retornar mais linhas do que qualquer uma das tabelas e como entrevistadores testam isso. Você pratica Coding Interview Prep com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Coding Interview Prep?

Nenhuma experiência prévia é necessária. Coding Interview Prep no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Expansão de junções e multiplicação de linhas”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Coding Interview Prep?

Sim. Cada aula de Coding Interview Prep inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Como INNER JOIN faz correspondência entre linhas
  2. ON versus WHERE em junções
  3. Expansão de junções e multiplicação de linhas
  4. Unindo três ou mais tabelas
← Voltar para Coding Interview Prep