Voltar para o conteúdo

sql para iniciantes

SQL para entrevistas: as 20 perguntas mais comuns (com respostas)

Prepare-se para entrevistas técnicas com as 20 perguntas de SQL mais cobradas em processos seletivos de analista de dados no Brasil — com respostas completas e exemplos de código.

Raphael Carvalho · 18 de mar. de 2026 · 16 min de leitura

Resumo rápido

  • As perguntas de SQL em entrevistas se concentram em JOINs, GROUP BY, subqueries, CTEs e funções de janela.
  • A maioria das avaliações técnicas júnior testa 5 a 7 conceitos centrais — dominar esses elimina 80% do estresse da prova.
  • Saber explicar o raciocínio por trás da query importa tanto quanto escrever a sintaxe correta.

A etapa técnica de SQL em processos seletivos assusta muita gente — mas a realidade é que a maioria das avaliações testa um conjunto relativamente pequeno de conceitos. Quem domina esses conceitos e sabe explicar o próprio raciocínio passa na grande maioria dos processos para analista de dados.

Este guia reúne as 20 perguntas de SQL mais cobradas em entrevistas técnicas no Brasil, com respostas completas e exemplos de código. Use como checklist de preparação.


Como as entrevistas técnicas de SQL funcionam

Existem três formatos principais:

1. Teste assíncrono (HackerRank, StrataScratch, LeetCode SQL) Você recebe um problema e tem um tempo para resolver. O código é avaliado automaticamente. Foco em acertar a saída correta.

2. Teste enviado por e-mail Um conjunto de queries para escrever, geralmente em cima de um schema enviado junto. Você retorna um arquivo SQL ou planilha com as respostas.

3. Live coding com entrevistador O formato mais exigente. Você resolve o problema em tempo real, compartilhando a tela. O entrevistador pode fazer perguntas, pedir explicações e introduzir variações do problema.

Para os três formatos, o mesmo conjunto de habilidades é testado. A diferença é que no live coding, a capacidade de explicar o raciocínio é tão importante quanto a solução em si.


As 20 perguntas mais comuns

Usaremos um schema simplificado ao longo dos exemplos:

-- Tabelas de referência
clientes (id_cliente, nome, cidade, data_cadastro)
pedidos (id_pedido, id_cliente, data_pedido, valor_total, status)
produtos (id_produto, nome_produto, categoria, preco_unitario)
itens_pedido (id_pedido, id_produto, quantidade, preco_unitario)
vendedores (id_vendedor, nome, regiao, data_admissao)
pedidos_vendedor (id_pedido, id_vendedor)

1. Qual a diferença entre INNER JOIN, LEFT JOIN e RIGHT JOIN?

Resposta conceitual:

  • INNER JOIN — retorna apenas as linhas que têm correspondência em ambas as tabelas
  • LEFT JOIN — retorna todas as linhas da tabela da esquerda, com NULL onde não há correspondência na direita
  • RIGHT JOIN — o inverso do LEFT JOIN (raramente usado na prática; geralmente reescrito como LEFT JOIN)

Exemplo prático:

-- INNER JOIN: apenas clientes que têm pedidos
SELECT c.nome, COUNT(p.id_pedido) AS total_pedidos
FROM clientes c
INNER JOIN pedidos p ON c.id_cliente = p.id_cliente
GROUP BY c.nome;

-- LEFT JOIN: todos os clientes, incluindo os sem pedidos (retornam NULL)
SELECT c.nome, COUNT(p.id_pedido) AS total_pedidos
FROM clientes c
LEFT JOIN pedidos p ON c.id_cliente = p.id_cliente
GROUP BY c.nome;

Como responder na entrevista: explique o conceito, depois mostre que sabe quando usar cada um. Casos onde LEFT JOIN é necessário (clientes sem pedidos, produtos sem vendas) são mais comuns na prática do que INNER JOIN puro.


2. Qual a diferença entre WHERE e HAVING?

Resposta:

  • WHERE filtra linhas antes da agregação
  • HAVING filtra grupos depois da agregação
-- Clientes que fizeram mais de 5 pedidos com valor total acima de R$ 1.000
SELECT id_cliente, COUNT(*) AS qtd_pedidos, SUM(valor_total) AS total_gasto
FROM pedidos
WHERE status = 'concluido'          -- WHERE: filtra linhas antes de agrupar
GROUP BY id_cliente
HAVING COUNT(*) > 5                 -- HAVING: filtra grupos depois de agrupar
   AND SUM(valor_total) > 1000;

Erro comum que o entrevistador vai testar: tentar usar uma função de agregação no WHERE — isso gera erro. Se a condição usa COUNT, SUM, AVG, etc., ela vai no HAVING.

Veja mais sobre esse tópico em nosso artigo sobre quando usar WHERE vs HAVING.


3. Como encontrar duplicatas em uma tabela?

-- Encontrar e-mails duplicados na tabela de clientes
SELECT email, COUNT(*) AS ocorrencias
FROM clientes
GROUP BY email
HAVING COUNT(*) > 1
ORDER BY ocorrencias DESC;

Variação comum: “Como deletar as duplicatas mantendo apenas um registro?” — isso envolve CTEs com ROW_NUMBER(), que aparece mais em vagas plenas.


4. Como funciona o GROUP BY? Quais colunas podem aparecer no SELECT?

Resposta: GROUP BY agrupa linhas com o mesmo valor nas colunas especificadas. No SELECT, só podem aparecer:

  • Colunas que estão no GROUP BY
  • Funções de agregação (COUNT, SUM, AVG, MIN, MAX)
-- Receita total por categoria de produto em 2025
SELECT
    p.categoria,
    SUM(ip.quantidade * ip.preco_unitario) AS receita_total,
    COUNT(DISTINCT ip.id_pedido) AS num_pedidos
FROM itens_pedido ip
JOIN produtos p ON ip.id_produto = p.id_produto
JOIN pedidos ped ON ip.id_pedido = ped.id_pedido
WHERE YEAR(ped.data_pedido) = 2025
GROUP BY p.categoria
ORDER BY receita_total DESC;

5. O que é uma subquery? Quando usar subquery vs JOIN?

Subquery é uma query dentro de outra query, usada no WHERE, FROM ou SELECT.

-- Clientes que gastaram acima da média geral
SELECT nome, total_gasto
FROM (
    SELECT c.nome, SUM(p.valor_total) AS total_gasto
    FROM clientes c
    JOIN pedidos p ON c.id_cliente = p.id_cliente
    GROUP BY c.nome
) resumo_clientes
WHERE total_gasto > (SELECT AVG(valor_total) FROM pedidos);

Quando usar subquery vs JOIN:

  • Use JOIN quando precisa de colunas de múltiplas tabelas
  • Use subquery quando o resultado da subconsulta é um valor escalar ou uma lista de referência
  • Em termos de performance, JOIN geralmente é mais eficiente para grandes volumes

6. O que é uma CTE (WITH) e por que usá-la?

CTE (Common Table Expression) é uma query nomeada temporária definida antes da query principal com WITH. Não existe no banco — é calculada na hora da execução.

-- Receita por cliente e ranking dentro da cidade
WITH receita_por_cliente AS (
    SELECT
        c.id_cliente,
        c.nome,
        c.cidade,
        SUM(p.valor_total) AS receita_total
    FROM clientes c
    JOIN pedidos p ON c.id_cliente = p.id_cliente
    WHERE p.status = 'concluido'
    GROUP BY c.id_cliente, c.nome, c.cidade
)
SELECT
    nome,
    cidade,
    receita_total,
    RANK() OVER (PARTITION BY cidade ORDER BY receita_total DESC) AS ranking_cidade
FROM receita_por_cliente;

Por que usar CTEs:

  1. Legibilidade — quebra queries complexas em partes nomeadas
  2. Reutilização — pode referenciar a mesma CTE múltiplas vezes
  3. Recursividade — CTEs recursivas para hierarquias (avançado)

7. Quais funções de janela você conhece? Como ROW_NUMBER difere de RANK?

Funções de janela calculam valores em relação a um “janela” de linhas sem colapsar os resultados em grupos.

SELECT
    nome,
    regiao,
    receita_total,
    ROW_NUMBER() OVER (PARTITION BY regiao ORDER BY receita_total DESC) AS row_num,
    RANK()       OVER (PARTITION BY regiao ORDER BY receita_total DESC) AS rank_posicao,
    DENSE_RANK() OVER (PARTITION BY regiao ORDER BY receita_total DESC) AS dense_rank
FROM vendas_por_vendedor;

Diferença:

  • ROW_NUMBER — número sequencial único, sem empates (dois valores iguais recebem números diferentes)
  • RANK — empates recebem o mesmo número, e o próximo pula (1, 2, 2, 4)
  • DENSE_RANK — empates recebem o mesmo número, sem pular (1, 2, 2, 3)

8. Como calcular a diferença entre o valor atual e o anterior (variação período a período)?

-- Receita mensal e variação percentual em relação ao mês anterior
WITH receita_mensal AS (
    SELECT
        DATE_TRUNC('month', data_pedido) AS mes,
        SUM(valor_total) AS receita
    FROM pedidos
    WHERE status = 'concluido'
    GROUP BY DATE_TRUNC('month', data_pedido)
)
SELECT
    mes,
    receita,
    LAG(receita) OVER (ORDER BY mes) AS receita_mes_anterior,
    ROUND(
        (receita - LAG(receita) OVER (ORDER BY mes)) /
        LAG(receita) OVER (ORDER BY mes) * 100, 2
    ) AS variacao_pct
FROM receita_mensal
ORDER BY mes;

LAG() acessa o valor da linha anterior. LEAD() acessa o valor da linha seguinte. São clássicos em análises de tendência.


9. Como encontrar o segundo maior valor em uma coluna?

Essa pergunta aparece em muitos processos como teste de conhecimento de funções de janela ou subqueries.

-- Abordagem 1: com subquery (mais comum em banco de dados que não suportam LIMIT + OFFSET)
SELECT MAX(valor_total) AS segundo_maior
FROM pedidos
WHERE valor_total < (SELECT MAX(valor_total) FROM pedidos);

-- Abordagem 2: com DENSE_RANK (mais robusta e recomendada)
SELECT valor_total
FROM (
    SELECT valor_total,
           DENSE_RANK() OVER (ORDER BY valor_total DESC) AS dr
    FROM pedidos
) ranked
WHERE dr = 2
LIMIT 1;

Dica de entrevista: sempre pergunte “como tratar empates?” O entrevistador quer ver que você pensa nos edge cases.


10. Como funciona o CASE WHEN?

CASE WHEN é o equivalente de um if/else no SQL. Cria colunas calculadas com lógica condicional.

-- Classificar clientes por volume de compras
SELECT
    c.nome,
    SUM(p.valor_total) AS total_gasto,
    CASE
        WHEN SUM(p.valor_total) >= 10000 THEN 'VIP'
        WHEN SUM(p.valor_total) >= 5000  THEN 'Premium'
        WHEN SUM(p.valor_total) >= 1000  THEN 'Regular'
        ELSE 'Novo'
    END AS categoria_cliente
FROM clientes c
LEFT JOIN pedidos p ON c.id_cliente = p.id_cliente
GROUP BY c.nome
ORDER BY total_gasto DESC;

11. Qual a diferença entre COUNT(*), COUNT(coluna) e COUNT(DISTINCT coluna)?

SELECT
    COUNT(*)                    AS total_linhas,        -- conta todas as linhas
    COUNT(id_cliente)           AS clientes_com_pedido, -- exclui NULLs
    COUNT(DISTINCT id_cliente)  AS clientes_unicos       -- conta valores únicos
FROM pedidos;

Erro comum: usar COUNT(*) quando a pergunta é “quantos clientes distintos”. O entrevistador vai testar isso.


12. Como fazer um self join? Quando isso é necessário?

Self join é quando uma tabela faz JOIN com ela mesma. Útil para comparar linhas dentro da mesma tabela ou navegar hierarquias.

-- Listar empregados com seus respectivos gerentes
SELECT
    e.nome AS funcionario,
    g.nome AS gerente
FROM funcionarios e
LEFT JOIN funcionarios g ON e.id_gerente = g.id_funcionario
ORDER BY gerente, funcionario;

13. Como calcular uma média móvel?

-- Média móvel de 3 dias de receita
SELECT
    data_pedido,
    SUM(valor_total) AS receita_dia,
    AVG(SUM(valor_total)) OVER (
        ORDER BY data_pedido
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) AS media_movel_3d
FROM pedidos
WHERE status = 'concluido'
GROUP BY data_pedido
ORDER BY data_pedido;

A cláusula ROWS BETWEEN 2 PRECEDING AND CURRENT ROW define a janela como “as 2 linhas anteriores mais a atual”.


14. O que é um índice e como ele afeta a performance?

Resposta conceitual para entrevistas: Um índice é uma estrutura de dados auxiliar que o banco mantém para acelerar consultas em colunas específicas. Funciona como o índice de um livro: em vez de ler tudo, o banco vai diretamente à posição certa.

Quando usar:

  • Colunas usadas frequentemente em WHERE, JOIN e ORDER BY
  • Colunas de foreign key

Quando não usar:

  • Tabelas pequenas (o overhead não compensa)
  • Colunas que sofrem muitas atualizações (índice precisa ser reconstruído a cada escrita)

15. Como fazer UNION vs UNION ALL?

-- UNION: remove duplicatas (mais lento)
SELECT cidade FROM clientes
UNION
SELECT cidade FROM fornecedores;

-- UNION ALL: mantém duplicatas (mais rápido)
SELECT cidade FROM clientes
UNION ALL
SELECT cidade FROM fornecedores;

Regra: as queries combinadas precisam ter o mesmo número de colunas e tipos compatíveis. Prefira UNION ALL quando souber que não há duplicatas ou quando elas são desejadas.


16. Como deletar registros duplicados mantendo apenas o mais recente?

-- Manter apenas o registro mais recente para cada e-mail
DELETE FROM clientes
WHERE id_cliente NOT IN (
    SELECT MAX(id_cliente)
    FROM clientes
    GROUP BY email
);

Variação com CTE (mais legível):

WITH duplicatas AS (
    SELECT id_cliente,
           ROW_NUMBER() OVER (PARTITION BY email ORDER BY data_cadastro DESC) AS rn
    FROM clientes
)
DELETE FROM clientes
WHERE id_cliente IN (SELECT id_cliente FROM duplicatas WHERE rn > 1);

17. O que é NULL e como tratar corretamente?

Pontos importantes:

  • NULL não é zero, não é string vazia — é ausência de valor
  • NULL = NULL retorna NULL (não TRUE) — use IS NULL ou IS NOT NULL
  • Funções como COALESCE e NULLIF ajudam a tratar NULLs
-- COALESCE: retorna o primeiro valor não nulo
SELECT nome, COALESCE(telefone, 'Não informado') AS telefone_formatado
FROM clientes;

-- NULLIF: retorna NULL se dois valores são iguais (evita divisão por zero)
SELECT receita / NULLIF(custo, 0) AS margem
FROM produtos;

18. Como calcular percentual de um total?

-- Participação de cada categoria na receita total
SELECT
    p.categoria,
    SUM(ip.quantidade * ip.preco_unitario) AS receita,
    ROUND(
        SUM(ip.quantidade * ip.preco_unitario) * 100.0 /
        SUM(SUM(ip.quantidade * ip.preco_unitario)) OVER (),
        2
    ) AS pct_receita
FROM itens_pedido ip
JOIN produtos p ON ip.id_produto = p.id_produto
GROUP BY p.categoria
ORDER BY receita DESC;

O SUM(...) OVER () sem partição calcula o total geral — a janela abrange todas as linhas.


19. Qual a diferença entre TRUNCATE e DELETE?

DELETETRUNCATE
Remove linhas específicasSim (com WHERE)Não — remove todas
Pode ser revertidoSim (se dentro de transação)Depende do banco
VelocidadeMais lento (log por linha)Muito mais rápido
Reseta auto-incrementNãoSim (na maioria dos bancos)
Dispara triggersSimNão

20. Como otimizar uma query lenta?

Essa pergunta aparece em vagas plenas e sênior. Uma resposta estruturada:

1. Identifique o gargalo com EXPLAIN / EXPLAIN ANALYZE

EXPLAIN ANALYZE
SELECT c.nome, COUNT(p.id_pedido)
FROM clientes c
JOIN pedidos p ON c.id_cliente = p.id_cliente
GROUP BY c.nome;

2. Verifique a presença de índices nas colunas usadas em JOIN, WHERE e ORDER BY

3. Evite SELECT * — selecione apenas as colunas necessárias

4. Substitua subqueries correlacionadas por JOINs quando possível

5. Use EXISTS em vez de IN para listas grandes

6. Limite o volume de dados antes de fazer JOINs — filtre o máximo possível nas subqueries ou CTEs antes de combinar tabelas grandes


Como se preparar para a etapa técnica de SQL

O maior erro na preparação é estudar muita teoria e praticar pouco. Avaliações técnicas medem o que você consegue fazer, não o que você sabe explicar.

Uma rotina de preparação eficaz:

  1. Estude o conceito — entenda o que o comando faz e quando usá-lo
  2. Escreva a query — sem copiar, do zero, em cima de um dataset real
  3. Explique o raciocínio em voz alta — simule o live coding
  4. Varie o problema — o que muda se a pergunta for ligeiramente diferente?

Se você ainda está no começo, o artigo SQL para iniciantes: o guia completo é o ponto de partida antes de mergulhar nas perguntas de entrevista.


Pronto para ir além dos tutoriais?

Entrevistas técnicas cobram prática com dados reais em situações de pressão. A melhor preparação combina teoria bem fundamentada com exercícios progressivos que simulam os problemas que aparecem no trabalho.

O Curso SQL do Zero ao Avançado da Blast inclui módulos específicos de preparação para processos seletivos — com exercícios baseados nos tipos de perguntas que aparecem neste guia, em ambientes que simulam avaliações técnicas reais. É a preparação mais direta que existe para passar de forma consistente nas etapas técnicas de SQL.


Perguntas frequentes

Preciso saber todas as 20 perguntas para passar em uma vaga júnior?

Não. Para vagas júnior, as questões 1 a 9 cobrem a maioria dos processos. As questões 10 a 20 aparecem mais em vagas plenas e sênior, ou em empresas com bar técnico mais alto.

Qual banco de dados devo usar para praticar?

PostgreSQL é a melhor opção — é gratuito, open source, amplamente usado no mercado brasileiro e tem uma das implementações mais completas de SQL padrão. Instale localmente ou use o SQLFiddle para praticar online.

Existe alguma plataforma online para praticar perguntas de entrevista SQL?

Sim. StrataScratch, LeetCode (seção SQL), HackerRank e Mode Analytics têm coleções de problemas reais de entrevistas, classificados por dificuldade e empresa.

O entrevistador espera que eu acerte na primeira tentativa?

Não necessariamente — especialmente no live coding. O que o entrevistador avalia é a forma como você pensa no problema, como reage a erros e se consegue iterar até chegar na solução. Verbalizar o raciocínio é tão importante quanto o código.

Curso em português para brasileiros

SQL do Zero ao Avançado

A plataforma interativa de SQL feita para analistas. Pare de depender da fila de engenharia de dados.

Conheça o curso

Advertisement: SQL do Zero ao Avançado

Sobre o autor

Raphael Carvalho

Founder & Principal Consultant

Compartilhar Twitter LinkedIn

Leituras recomendadas