0Pricing
Coding Interview Prep · Aula

Reescrevendo subconsultas correlacionadas como junções

Converta lógica correlacionada em junções ou funções de janela para melhorar o desempenho.

Reescrevendo subconsultas correlacionadas como junções é uma aula grátis de Coding Interview Prep no CoddyKit. Esta é a aula 4 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.

Por que reescrever

As subconsultas correlacionadas são legíveis, mas podem ser lentas: a consulta interna pode ser executada uma vez para cada linha externa. Os entrevistadores costumam pedir que você reescreva uma como uma junção ou uma função de janela para melhorar o desempenho.

O objetivo é obter o mesmo resultado com uma única passagem pelos dados, em vez de fazer varreduras internas repetidas.

Conhecer dois ou três padrões de reescrita e saber quando cada um preserva a correção é uma habilidade essencial de nível intermediário.

Padrão 1: EXISTS para INNER JOIN

Uma consulta correlacionada com EXISTS que verifica pelo menos uma correspondência muitas vezes pode se tornar uma INNER JOIN.

Mas tenha cuidado: uma junção pode produzir linhas externas duplicadas quando várias linhas internas correspondem. Adicione DISTINCT ou faça uma agregação para restaurar uma linha por chave externa.

-- Correlated EXISTS
SELECT c.customer_id, c.name
FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o
             WHERE o.customer_id = c.customer_id);

-- Join rewrite (DISTINCT avoids dupes from fan-out)
SELECT DISTINCT c.customer_id, c.name
FROM customers c
JOIN orders o ON o.customer_id = c.customer_id;

A armadilha da multiplicação de linhas

O erro mais comum em uma reescrita é esquecer a multiplicação de linhas. EXISTS retorna cada cliente uma única vez, independentemente de quantos pedidos ele tenha. Uma junção ingênua retorna uma linha por pedido, inflando as contagens.

Se uma etapa posterior fizer COUNT(*) ou SUM(amount) sobre esse resultado unido sem agrupar cuidadosamente, os números estarão errados.

Sempre pergunte: a junção pode multiplicar as linhas? Se puder, use DISTINCT ou um GROUP BY para consolidá-las novamente.

Padrão 2: NOT EXISTS para LEFT JOIN / IS NULL

A reescrita de antijunção é um padrão garantido em entrevistas. Um NOT EXISTS correlacionado se torna um LEFT JOIN em que o lado direito é NULL.

As linhas externas sem correspondência recebem valores NULL no lado direito; filtrar por esse NULL mantém exatamente as linhas sem correspondência.

-- Correlated NOT EXISTS
SELECT c.customer_id FROM customers c
WHERE NOT EXISTS (SELECT 1 FROM orders o
                  WHERE o.customer_id = c.customer_id);

-- LEFT JOIN / IS NULL rewrite
SELECT c.customer_id
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.customer_id
WHERE o.customer_id IS NULL;

Escolha uma coluna que não seja NULL para testar

Na reescrita com LEFT JOIN / IS NULL, teste uma coluna do lado direito que nunca seja NULL em uma correspondência real, de preferência a chave de junção ou a chave primária.

Se você testar uma coluna que aceita NULL, não poderá distinguir uma não correspondência genuína (nenhuma linha) de uma linha correspondente que simplesmente tenha NULL nessa coluna. Esse erro retorna linhas incorretas.

Usar a chave de junção (aqui o.customer_id) ou o.order_id garante que NULL signifique "nenhuma linha correspondente".

Padrão 3: agregado escalar para JOIN + GROUP BY

Um agregado correlacionado em SELECT pode se tornar uma junção com uma subconsulta agrupada (uma tabela derivada).

Calcule o agregado por grupo uma única vez e depois faça a junção dele de volta às linhas de detalhe. A consulta interna é executada uma única vez, em vez de uma vez por linha.

-- Correlated scalar aggregate
SELECT e1.name,
       (SELECT MAX(e2.salary) FROM employees e2
        WHERE e2.dept_id = e1.dept_id) AS dept_max
FROM employees e1;

-- Join + GROUP BY rewrite
SELECT e.name, m.dept_max
FROM employees e
JOIN (SELECT dept_id, MAX(salary) AS dept_max
      FROM employees GROUP BY dept_id) m
  ON m.dept_id = e.dept_id;

Padrão 4: a reescrita com função de janela

Muitas vezes, a reescrita mais limpa é uma função de janela. MAX(salary) OVER (PARTITION BY dept_id) substitui completamente o agregado correlacionado, sem necessidade de junção.

Ela calcula o valor do grupo em uma única passagem e mantém todas as linhas de detalhe. Essa costuma ser a resposta que os entrevistadores mais querem ver em consultas analíticas.

SELECT name,
       dept_id,
       salary,
       MAX(salary) OVER (PARTITION BY dept_id) AS dept_max
FROM employees;

Reescrita do maior N por grupo

Uma subconsulta correlacionada que seleciona a primeira linha de cada grupo (salary = MAX per dept) pode ser reescrita de forma elegante com ROW_NUMBER.

Particione pelo grupo, ordene pela métrica e mantenha a classificação 1. Use RANK se quiser todas as linhas superiores empatadas.

SELECT name, dept_id, salary
FROM (
    SELECT name, dept_id, salary,
           ROW_NUMBER() OVER (PARTITION BY dept_id
                              ORDER BY salary DESC) AS rn
    FROM employees
) t
WHERE rn = 1;

Quando não reescrever

Reescrever nem sempre traz vantagem. Mantenha a subconsulta correlacionada quando:

  • O conjunto externo é pequeno, portanto o custo por linha é insignificante.
  • A coluna correlacionada está bem indexada e o otimizador já a transforma em uma semijunção eficiente.
  • A legibilidade é mais importante que a micro-otimização em código mantido.

Os otimizadores modernos frequentemente transformam EXISTS automaticamente em uma semijunção. Diga que você mediria com EXPLAIN antes de presumir que uma reescrita ajudará.

Verificação da equivalência

Depois de qualquer reescrita, confirme que ela retorna as mesmas linhas e a mesma cardinalidade que a versão original.

  • Verifique se as contagens de linhas coincidem.
  • Verifique se nenhuma duplicata foi introduzida pela multiplicação de linhas da junção.
  • Verifique se os casos extremos de NULL e de grupos vazios continuam funcionando corretamente.

Uma maneira rápida é executar as duas versões e aplicar EXCEPT em ambas as direções; um resultado vazio significa que elas concordam. Os entrevistadores valorizam que você verifique, em vez de presumir.

SELECT customer_id FROM query_a
EXCEPT
SELECT customer_id FROM query_b;
-- and the reverse; both empty => equivalent

Reescrevendo IN para uma junção

Uma subconsulta IN não correlacionada também costuma poder ser reescrita como uma junção, mas o mesmo alerta sobre multiplicação de linhas se aplica. IN elimina duplicatas de associação; uma junção não.

Se a lista interna tiver chaves duplicadas, a junção repetirá as linhas externas. Use DISTINCT no lado interno ou no resultado final para reproduzir a semântica de IN.

-- IN subquery
SELECT c.name FROM customers c
WHERE c.customer_id IN (SELECT o.customer_id FROM orders o);

-- Join rewrite, de-duplicated to match IN
SELECT DISTINCT c.name
FROM customers c
JOIN orders o ON o.customer_id = c.customer_id;

Verificação rápida

Escolha a reescrita correta com junção para uma antijunção correlacionada com NOT EXISTS.

Recapitulação: reescrevendo subconsultas correlacionadas como junções

Principais conclusões:

  • EXISTS → INNER JOIN (adicione DISTINCT para evitar duplicatas causadas pela multiplicação de linhas).
  • NOT EXISTS → LEFT JOIN ... WHERE key IS NULL (teste uma coluna que não aceite NULL).
  • Agregado escalar correlacionado → faça JOIN com uma tabela derivada agrupada ou, melhor ainda, use uma função de janela.
  • Primeiro por grupo → ROW_NUMBER (ou RANK para empates).
  • Verifique a equivalência e confira com EXPLAIN antes de presumir que uma reescrita é mais rápida.

Conhecer as duas formas e a armadilha da multiplicação de linhas é exatamente o que as entrevistas de nível intermediário procuram avaliar.

Perguntas Frequentes

A aula “Reescrevendo subconsultas correlacionadas como junções” é grátis?

Sim — o texto completo de “Reescrevendo subconsultas correlacionadas como junções” é 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 “Reescrevendo subconsultas correlacionadas como junções”?

Converta lógica correlacionada em junções ou funções de janela para melhorar o desempenho. 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 4 de 4.

Quanto tempo leva a aula “Reescrevendo subconsultas correlacionadas como junções”?

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. Anatomia de uma subconsulta correlacionada
  2. Agregações por grupo sem GROUP BY
  3. EXISTS e NOT EXISTS correlacionados
  4. Reescrevendo subconsultas correlacionadas como junções
← Voltar para Coding Interview Prep