CodeGym /Cursos /SQL SELF /Usando subqueries no SELECT

Usando subqueries no SELECT

SQL SELF
Nível 14, Lição 0
Disponível

Queria voltar rapidinho no assunto de subqueries no SELECT. Principalmente porque a query interna pode acessar dados da query externa. Parece simples, mas nem tanto. Bora mergulhar de novo nesse tema...

Subqueries no SELECT deixam você adicionar colunas extras com valores calculados ou dados que dependem de outros registros ou tabelas. Por exemplo, dá pra mostrar uma lista de estudantes com a média das notas deles, quantos cursos eles estão fazendo ou a nota máxima atual do grupo. Isso é útil quando você quer analisar dados "na hora", criando colunas-resumo sem precisar processar tudo antes.

O básico das subqueries no SELECT

Antes de ir pros exemplos, bora ver a sintaxe geral. Subqueries no SELECT ficam assim:

SELECT column1,
       column2,
       (SELECT agregacao_ou_condicao FROM outra_tabela WHERE condicao) AS novo_nome_coluna
FROM tabela_principal;

Repara que a subquery retorna um valor só, que aparece no resultado como uma nova coluna. E o condicao pode acessar colunas da tabela_principal.

Exemplo 1: Adicionando a média das notas do estudante

Bora começar com uma query simples e útil: temos a tabela students e a tabela grades, onde ficam as notas dos estudantes.

Tabela students:

id name
1 Alex Lin
2 Anna Song
3 Dan Seth

Tabela grades:

student_id grade
1 90
1 85
2 76
3 88
3 92

Agora queremos pegar a lista de estudantes com o nome e a média das notas. Pra isso, usamos uma subquery no SELECT:

SELECT
    s.id,
    s.name,
    (SELECT AVG(g.grade) 
     FROM grades g 
     WHERE g.student_id = s.id) AS average_grade
FROM students s;

Resultado:

id name average_grade
1 Alex Lin 87.5
2 Anna Song 76.0
3 Dan Seth 90.0

Aqui a subquery (SELECT AVG(g.grade) FROM grades g WHERE g.student_id = s.id) calcula a média das notas pra cada estudante. Ela retorna um valor pra cada linha da tabela students, e isso é prático quando você não quer fazer JOIN ou criar views antes.

Exemplo 2: Contando quantos cursos cada estudante faz

Agora bora adicionar info dos estudantes: quantos cursos eles estão fazendo. Pra isso temos mais tabelas:

Tabela enrollments:

student_id course_id
1 101
1 102
2 101

Vamos mostrar a lista de estudantes com a quantidade de cursos em que estão inscritos:

SELECT
    s.id,
    s.name,
    (SELECT COUNT(*)
     FROM enrollments e
     WHERE e.student_id = s.id) AS course_count -- referência pra tabela students da query externa
FROM students s;

Resultado:

id name course_count
1 Alex Lin 2
2 Anna Song 1
3 Dan Seth 0

A subquery (SELECT COUNT(*) FROM enrollments e WHERE e.student_id = s.id) conta quantos registros tem na tabela enrollments pra cada estudante.

Agregando dados em subqueries

É bem comum usar subqueries no SELECT pra calcular dados agregados. Funções como AVG, SUM, COUNT, MAX, MIN deixam você processar dados direto dentro de outras queries.

Exemplo 3: Soma total das notas do estudante

Bora adicionar a soma total das notas pra cada estudante. Pra isso, usamos uma subquery que soma todas as notas da tabela grades:

SELECT
    s.id,
    s.name,
    (SELECT SUM(g.grade)
     FROM grades g
     WHERE g.student_id = s.id) AS total_grade
FROM students s;

Resultado:

id name total_grade
1 Alex Lin 175
2 Anna Song 76
3 Dan Seth 180

Essa subquery (SELECT SUM(g.grade) FROM grades g WHERE g.student_id = s.id) soma as notas de cada estudante. Se o estudante não tiver nota, o resultado é NULL, porque SUM retorna NULL quando não tem valor nenhum.

Limitações e dicas

  1. Performance. Subqueries no SELECT rodam separadas pra cada linha da tabela principal. Isso pode deixar tudo bem lento se o volume de dados for grande. Se der, troca por JOIN ou usa dados agregados já prontos. Tipo assim:
SELECT
    s.id,
    s.name,
    g.total_grade
FROM students s
LEFT JOIN (
    SELECT student_id, SUM(grade) AS total_grade
    FROM grades
    GROUP BY student_id
) g ON s.id = g.student_id;

Esse jeito com JOIN é mais rápido, porque a agregação e soma rolam só uma vez.

2. Problemas com NULL.

Se não tiver dado na subquery, o resultado vai ser NULL. Isso pode pegar de surpresa. Exemplo:

SELECT
    s.id,
    s.name,
    (SELECT SUM(g.grade)
     FROM grades g
     WHERE g.student_id = s.id) AS total_grade
FROM students s;

Se o estudante não tiver registro em grades, o total_grade vai ser NULL. Pra trocar o NULL por 0, usa a função COALESCE:

SELECT
    s.id,
    s.name,
    COALESCE((SELECT SUM(g.grade)
              FROM grades g
              WHERE g.student_id = s.id), 0) AS total_grade
FROM students s;

Sim, aqui o primeiro parâmetro da função COALESCE é

(
    SELECT SUM(g.grade)
    FROM grades g
    WHERE g.student_id = s.id
)

Otimizando subqueries no SELECT

Pra evitar cálculos desnecessários e deixar tudo mais rápido:

  1. Cria índices nas colunas usadas nas subqueries. Por exemplo, indexar student_id na tabela grades acelera o filtro.
  2. Troca subqueries por dados agregados já prontos usando JOIN, se der.
  3. Limita a quantidade de dados processados nas subqueries usando filtro (WHERE).

Exemplo final: juntando várias subqueries

Bora juntar tudo e criar uma query que mostra o nome do estudante, média das notas, quantidade de cursos e soma total das notas:

SELECT
    s.id,
    s.name,
    (SELECT AVG(g.grade)
     FROM grades g
     WHERE g.student_id = s.id) AS average_grade,
    (SELECT COUNT(*) 
     FROM enrollments e 
     WHERE e.student_id = s.id) AS course_count,
    (SELECT SUM(g.grade)
     FROM grades g
     WHERE g.student_id = s.id) AS total_grade
FROM students s;

Essa query retorna o perfil completo do estudante, usando o poder das subqueries. A gente vê a média e soma das notas, e também quantos cursos cada um faz. Esse tipo de query é ótimo pra pegar info agregada rapidinho, sem precisar criar VIEW ou fazer JOIN separado.

id name average_grade course_count total_grade
1 Alex Lin 87.5 2 175
2 Anna Song 76.0 1 76
3 Dan Seth 90.0 0 180
2
Tarefa
SQL SELF, nível 14, lição 0
Bloqueado
Encontrar a média das notas dos estudantes
Encontrar a média das notas dos estudantes
2
Tarefa
SQL SELF, nível 14, lição 0
Bloqueado
Contar a quantidade de cursos para cada estudante
Contar a quantidade de cursos para cada estudante
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION