🧚 Ei! O Beekeeper Studio é uma GUI de banco de dados rápida, moderna e open source Download
7 de janeiro de 2026 Por Lucas Gray

Uma subquery é uma consulta aninhada dentro de outra consulta. Uma CTE (common table expression) é essa mesma consulta interna movida para o topo da instrução com WITH e com um nome, para que uma consulta longa seja lida como uma série de etapas. Os exemplos funcionam em PostgreSQL, MySQL, SQLite e SQL Server.

Como usar CTEs e subqueries

Uma subquery fica onde é usada: no FROM ela funciona como uma tabela, e no WHERE ou SELECT ela fornece um valor ou uma lista. Uma CTE é definida primeiro e depois usada como uma tabela pela consulta que vem em seguida:

-- Subquery: written where it's used
SELECT columns FROM (SELECT ...) AS name;

-- CTE: named first, then used like a table
WITH name AS (SELECT ...)
SELECT columns FROM name;
SELECT n * 2 AS doubled FROM (SELECT 21 AS n) AS numbers;
-- Output: 42

WITH numbers AS (SELECT 21 AS n)
SELECT n * 2 AS doubled FROM numbers;
-- Output: 42

Em uma tabela real, as duas formas retornam as mesmas linhas. Veja um filtro escrito das duas maneiras:

-- Input: people
-- first_name | last_name | job      | favorite_food
-- -----------+-----------+----------+--------------
-- Matthew    | Ortiz     | Chef     | cheese
-- Matt       | Novak     | Pilot    | pizza
-- Mattie     | Brooks    | Engineer | cheese
-- Priya      | Nair      | Teacher  | cheese

-- Subquery
SELECT *
FROM (SELECT first_name, last_name, job FROM people WHERE favorite_food = 'cheese') AS cheese_lovers
WHERE first_name LIKE 'Matt%';

-- CTE
WITH cheese_lovers AS (
  SELECT first_name, last_name, job FROM people WHERE favorite_food = 'cheese'
)
SELECT * FROM cheese_lovers
WHERE first_name LIKE 'Matt%';

-- Output of both:
-- first_name | last_name | job
-- -----------+-----------+---------
-- Matthew    | Ortiz     | Chef
-- Mattie     | Brooks    | Engineer

Regras importantes

  • Uma CTE só dura uma instrução. A consulta logo após o WITH pode usá-la; a instrução seguinte não. Para manter um resultado em várias consultas, use uma tabela temporária ou uma view.
  • Dê um nome à subquery no FROM, como AS numbers acima. MySQL e SQL Server rejeitam a subquery sem nome.
  • Uma subquery usada como valor único deve retornar uma linha:
SELECT (SELECT 1 UNION ALL SELECT 2) AS n;
-- ERROR: more than one row returned by a subquery used as an expression
-- (SQLite doesn't complain: it quietly uses the first row, 1)
  • A velocidade costuma ser a mesma. Em geral, os bancos de dados planejam uma CTE usada uma única vez da mesma forma que a subquery equivalente, então escolha a que for mais legível.

Sintaxe alternativa

Uma CTE que faz referência a si mesma (veja abaixo) é escrita com WITH RECURSIVE:

-- In SQL Server, leave out RECURSIVE
WITH RECURSIVE counter AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1 FROM counter WHERE n < 3
)
SELECT n FROM counter;

-- Output:
-- n
-- -
-- 1
-- 2
-- 3

No SQL Server, a instrução antes de um WITH deve terminar com ponto e vírgula, e é por isso que código T-SQL muitas vezes começa uma CTE com ;WITH.

Quando usar uma CTE em vez de uma subquery?

Uma subquery funciona bem para uma etapa pequena. Mude para uma CTE quando a consulta tiver várias etapas, precisar do mesmo resultado duas vezes ou tiver que fazer referência a si mesma.

Filtrar por um valor calculado

Quando a consulta interna só produz um valor ou uma lista para comparação, como o total médio dos pedidos, uma subquery no WHERE é a forma mais curta de escrever. Uma CTE também funcionaria, mas adiciona um nome que ninguém precisa.

Dividir uma consulta longa em etapas nomeadas

Quando uma consulta tem estágios (total por cliente, depois os primeiros colocados, depois a lista final), dê um nome a cada estágio. Liste várias CTEs após um único WITH, separadas por vírgulas: cada uma pode usar as anteriores, e a consulta é lida de cima para baixo em vez de dentro para fora.

Usar o mesmo resultado mais de uma vez

Uma instrução pode fazer referência a uma CTE quantas vezes quiser, então um resultado que você precisa duas vezes (uma lista de totais e sua média, ou cada total e o total geral) é escrito uma só vez. Com subqueries, você teria que copiar toda a consulta interna.

Percorrer uma hierarquia

Só uma CTE pode fazer referência a si mesma. Uma CTE recursiva começa a partir de algumas linhas e continua fazendo join com a tabela até não aparecerem novas linhas. É assim que você percorre um organograma ou uma árvore de categorias, ou gera uma série de números ou datas.

Exemplos reais de CTEs e subqueries

Produtos com preço acima da média da categoria

A subquery faz referência a p.category da consulta externa, então ela é calculada para a categoria de cada produto (uma subquery correlacionada):

-- Input: products
-- name          | category  | price
-- --------------+-----------+-------
-- Desk Lamp     | Lighting  | 24.99
-- Floor Lamp    | Lighting  | 89.00
-- Office Chair  | Furniture | 149.00
-- Standing Desk | Furniture | 399.00
-- Bookshelf     | Furniture | 120.00

SELECT name, category, price
FROM products p
WHERE price > (
  SELECT AVG(price) FROM products WHERE category = p.category
)
ORDER BY category, name;

-- Output:
-- name          | category  | price
-- --------------+-----------+-------
-- Standing Desk | Furniture | 399.00
-- Floor Lamp    | Lighting  | 89.00

O produto mais vendido de cada categoria

Três etapas, cada uma com um nome: somar as unidades por produto, ranquear os produtos dentro de cada categoria e manter o primeiro:

-- Input: sales
-- id | product      | category  | units
-- ---+--------------+-----------+------
-- 1  | Desk Lamp    | Lighting  | 3
-- 2  | Floor Lamp   | Lighting  | 5
-- 3  | Desk Lamp    | Lighting  | 4
-- 4  | Office Chair | Furniture | 2
-- 5  | Bookshelf    | Furniture | 6

WITH product_totals AS (
  SELECT category, product, SUM(units) AS units
  FROM sales
  GROUP BY category, product
),
ranked AS (
  SELECT category, product, units,
         RANK() OVER (PARTITION BY category ORDER BY units DESC) AS place
  FROM product_totals
)
SELECT category, product, units
FROM ranked
WHERE place = 1
ORDER BY category;

-- Output:
-- category  | product   | units
-- ----------+-----------+------
-- Furniture | Bookshelf | 6
-- Lighting  | Desk Lamp | 7

A participação de cada região nas vendas

region_totals é usada duas vezes: uma para as linhas e outra dentro de uma subquery para o total geral:

-- Input: orders
-- id | region | amount
-- ---+--------+--------
-- 1  | North  | 1200.00
-- 2  | South  | 450.00
-- 3  | North  | 300.00
-- 4  | West   | 800.00
-- 5  | South  | 250.00

WITH region_totals AS (
  SELECT region, SUM(amount) AS total
  FROM orders
  GROUP BY region
)
SELECT
  region,
  total,
  ROUND(100.0 * total / (SELECT SUM(total) FROM region_totals), 1) AS pct_of_sales
FROM region_totals
ORDER BY total DESC;

-- Output:
-- region | total   | pct_of_sales
-- -------+---------+-------------
-- North  | 1500.00 | 50.0
-- West   | 800.00  | 26.7
-- South  | 700.00  | 23.3

Escrita com subqueries, a consulta com GROUP BY apareceria duas vezes.

A cadeia de gestores de um funcionário

Comece a partir de um funcionário e siga o manager_id para cima até acabar:

-- Input: employees
-- id | name      | manager_id
-- ---+-----------+-----------
-- 1  | Maya Chen | NULL
-- 2  | Sam Ortiz | 1
-- 3  | Jo Kim    | 2
-- 4  | Lee Ross  | 2
-- 5  | Ana Diaz  | 1

-- In SQL Server, leave out RECURSIVE
WITH RECURSIVE chain AS (
  SELECT id, name, manager_id, 0 AS level
  FROM employees
  WHERE name = 'Jo Kim'
  UNION ALL
  SELECT e.id, e.name, e.manager_id, chain.level + 1
  FROM employees e
  JOIN chain ON e.id = chain.manager_id
)
SELECT level, name FROM chain ORDER BY level;

-- Output:
-- level | name
-- ------+----------
-- 0     | Jo Kim
-- 1     | Sam Ortiz
-- 2     | Maya Chen

Leitura complementar sobre CTEs e subqueries

Neste blog:

Documentação oficial:

Beekeeper Studio é um cliente de banco de dados gratuito e open source

A melhor ferramenta de consultas e edição de SQL que já usei. Tem tudo o que preciso para gerenciar meu banco de dados. - ⭐⭐⭐⭐⭐ Mit

O Beekeeper Studio é rápido, intuitivo e fácil de usar. Ele suporta vários bancos de dados e funciona muito bem no Windows, Mac e Linux.

A versão do Beekeeper para Linux tem 100% dos recursos, sem atalhos e sem concessões.

O que os usuários dizem sobre o Beekeeper Studio

★★★★★
"O Beekeeper Studio substituiu completamente meu antigo fluxo de trabalho com SQL. É rápido, intuitivo e torna o trabalho com bancos de dados agradável de novo."
— Alex K., Desenvolvedor de Banco de Dados
★★★★★
"Já experimentei muitas GUIs de banco de dados, mas o Beekeeper encontra o equilíbrio perfeito entre recursos e simplicidade. Simplesmente funciona."
— Sarah M., Engenheira Full Stack

Pronto para melhorar seu fluxo de trabalho com SQL?

download Baixe grátis