Aprenda / SQL e banco de dados

IntermediárioAula 9 de 1616 min0% da trilha

Subqueries e CTEs (WITH)

Uma consulta dentro de outra — e o WITH que existe pra você não precisar empilhar parênteses até perder a conta.

Às vezes uma consulta depende do resultado de outra consulta. "Produtos mais caros que a média" não dá pra responder com um número fixo no WHERE — a média em si já é uma consulta. Uma subquery é exatamente isso: uma consulta SQL dentro de outra.

Subquery no WHERE — um valor calculado antes de comparar

SQL
SELECT nome, preco
FROM produtos
WHERE preco > (SELECT AVG(preco) FROM produtos);

A subquery entre parênteses roda primeiro, calcula um único valor (a média de todos os preços), e só depois a consulta de fora compara o preço de cada linha contra esse valor. Não tem nada de mágico — é sequencial: primeiro resolve o que está dentro dos parênteses, depois usa o resultado.

Subquery no FROM — tratar um resultado como se fosse uma tabela

SQL
SELECT categoria, media_preco
FROM (
  SELECT categoria, AVG(preco) AS media_preco
  FROM produtos
  GROUP BY categoria
) AS resumo_categoria
WHERE media_preco > 100;

Aqui a subquery entre parênteses vira uma tabela temporária (por isso precisa de um apelido, AS resumo_categoria), e a consulta de fora filtra em cima dela. Funciona, mas repare que já ficou mais difícil de ler — e isso só piora se você precisar de uma subquery dentro da subquery.

CTE (WITH) — o mesmo resultado, com nome

SQL — mesmo resultado da consulta anterior
WITH resumo_categoria AS (
  SELECT categoria, AVG(preco) AS media_preco
  FROM produtos
  GROUP BY categoria
)
SELECT categoria, media_preco
FROM resumo_categoria
WHERE media_preco > 100;

Uma CTE (Common Table Expression, declarada com WITH) faz exatamente o que a subquery no FROM fazia — só que com nome, declarada antes da consulta principal em vez de aninhada dentro dela. O banco executa do mesmo jeito; a diferença é só legibilidade: você lê de cima pra baixo, um passo por vez, em vez de decifrar parênteses aninhados.

Quando a CTE vale mais que a subquery

Pra uma comparação simples como a primeira desta lição, subquery no WHERE já é suficiente — não vale complicar. A CTE compensa quando você tem vários passos encadeados, ou quando o mesmo resultado intermediário seria reaproveitado mais de uma vez na consulta: nomear o passo deixa claro o que cada parte da consulta representa, em vez de forçar quem lê a montar mentalmente uma subquery dentro de outra dentro de outra.

Exercício

Usando uma CTE, escreva a consulta que lista nome e total gasto dos usuários que gastaram mais que a média de gasto entre todos os usuários (some quantidade × preco_unitario de itens_pedido, via pedidos).

Quiz rápido

Qual a principal vantagem de uma CTE (WITH) sobre uma subquery aninhada dentro de outra?
Na subquery SELECT * FROM produtos WHERE preco > (SELECT AVG(preco) FROM produtos), o que a subquery calcula?