Percorrendo uma árvore de categorias
Expanda completamente as árvores de pai e filho.
Percorrendo uma árvore de categorias é uma aula grátis de SQL Academy no CoddyKit. Esta é a aula 2 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 SQL Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de SQL Academy inclui 4 aulas no total.
O que é uma árvore de categorias?
Muitos conjuntos de dados do mundo real têm uma relação entre pai e filho. Um catálogo de produtos pode ter categorias como Eletrônicos → Telefones → Telefones inteligentes. Cada nó tem um pai, formando uma estrutura em árvore.
No SQL, isso normalmente é armazenado como uma tabela autorreferente: cada linha tem um id e um parent_id que aponta para outra linha da mesma tabela.
CREATE TABLE categories (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
parent_id INT REFERENCES categories(id)
);Dados de exemplo de categorias
Vamos preencher uma pequena árvore de categorias. O nó raiz tem parent_id = NULL porque não tem pai. Todos os outros nós apontam para seu pai por meio de um parent_id não nulo.
INSERT INTO categories (id, name, parent_id) VALUES
(1, 'Electronics', NULL),
(2, 'Phones', 1),
(3, 'Laptops', 1),
(4, 'Smartphones', 2),
(5, 'Feature Phones', 2),
(6, 'Gaming Laptops', 3),
(7, 'Ultrabooks', 3);O problema das consultas simples
Um SELECT simples só consegue buscar um nível por vez. Para alcançar três níveis de profundidade, seriam necessárias três consultas separadas ou três junções autorreferentes, o que se torna inviável à medida que a árvore cresce.
WITH RECURSIVE resolve esse problema ao permitir que uma consulta faça referência à própria saída, percorrendo a árvore nível a nível até que nenhuma nova linha seja encontrada.
-- This only shows direct children of Electronics (level 1)
SELECT id, name
FROM categories
WHERE parent_id = 1;Anatomia de WITH RECURSIVE
Uma CTE recursiva tem duas partes separadas por UNION ALL:
1. Membro âncora — um SELECT normal que fornece as linhas iniciais.
2. Membro recursivo — um SELECT que faz uma junção da CTE consigo mesma, produzindo o próximo nível a cada iteração.
O mecanismo repete o membro recursivo até que ele não retorne nenhuma linha.
WITH RECURSIVE cte AS (
-- Anchor: starting rows
SELECT ...
UNION ALL
-- Recursive: join cte to base table
SELECT ... FROM base_table JOIN cte ON ...
)
SELECT * FROM cte;Percorrendo a árvore completa a partir da raiz
Comece pela raiz (onde parent_id IS NULL) e percorra todos os descendentes. O membro recursivo faz uma junção de cada linha acumulada novamente com categories, usando a relação entre pai e filho.
WITH RECURSIVE category_tree AS (
-- Anchor: root nodes
SELECT id, name, parent_id, 1 AS depth
FROM categories
WHERE parent_id IS NULL
UNION ALL
-- Recursive: children of current level
SELECT c.id, c.name, c.parent_id, ct.depth + 1
FROM categories c
JOIN category_tree ct ON ct.id = c.parent_id
)
SELECT id, name, depth
FROM category_tree
ORDER BY depth, id;Rastreando o caminho
É útil registrar o caminho completo da raiz até cada nó. Podemos construir uma cadeia de caracteres path concatenando os nomes dos ancestrais à medida que avançamos na recursão.
Assim, fica fácil exibir trilhas de navegação como Eletrônicos / Telefones / Smartphones.
WITH RECURSIVE category_tree AS (
SELECT id, name, parent_id,
name AS path
FROM categories
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id,
ct.path || ' / ' || c.name
FROM categories c
JOIN category_tree ct ON ct.id = c.parent_id
)
SELECT id, name, path
FROM category_tree
ORDER BY path;Começando por um nó específico
Não é necessário começar pela raiz. Alterando a cláusula WHERE da âncora, você pode percorrer a subárvore de qualquer nó. Aqui, começamos por Telefones (id = 2) e recuperamos todos os seus descendentes.
WITH RECURSIVE subtree AS (
SELECT id, name, parent_id, 0 AS depth
FROM categories
WHERE id = 2 -- start at Phones
UNION ALL
SELECT c.id, c.name, c.parent_id, s.depth + 1
FROM categories c
JOIN subtree s ON s.id = c.parent_id
)
SELECT id, name, depth
FROM subtree
ORDER BY depth, id;Percorrendo para cima: encontrando todos os ancestrais
A árvore também pode ser percorrida no sentido inverso — subindo de uma folha até a raiz. Basta inverter a junção para seguir parent_id para cima, em vez de para baixo. Isso é útil quando você precisa da trilha de navegação completa para um nó folha conhecido.
WITH RECURSIVE ancestors AS (
SELECT id, name, parent_id
FROM categories
WHERE id = 4 -- start at Smartphones
UNION ALL
SELECT c.id, c.name, c.parent_id
FROM categories c
JOIN ancestors a ON a.parent_id = c.id
)
SELECT id, name
FROM ancestors
ORDER BY id;Adicionando uma exibição indentada
Um padrão comum de interface do usuário é indentar visualmente os nós filhos. Podemos usar REPEAT (ou LPAD) junto com a coluna depth para prefixar cada nome com espaços, produzindo uma visualização de árvore baseada em texto.
WITH RECURSIVE category_tree AS (
SELECT id, name, parent_id, 0 AS depth
FROM categories
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id, ct.depth + 1
FROM categories c
JOIN category_tree ct ON ct.id = c.parent_id
)
SELECT
REPEAT(' ', depth) || name AS indented_name,
depth
FROM category_tree
ORDER BY path;Evitando laços infinitos
Se os seus dados contiverem um ciclo (A é pai de B, B é pai de A), a recursão será executada indefinidamente e causará uma falha. Você pode evitar isso mantendo os identificadores visitados em um vetor e interrompendo a execução quando o identificador atual já estiver presente.
WITH RECURSIVE safe_tree AS (
SELECT id, name, parent_id,
ARRAY[id] AS visited
FROM categories
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id,
st.visited || c.id
FROM categories c
JOIN safe_tree st ON st.id = c.parent_id
WHERE c.id <> ALL(st.visited) -- stop if already seen
)
SELECT id, name FROM safe_tree;Contando os descendentes de cada nó
Depois de obter a árvore completa, você pode agregá-la. Aqui, contamos quantos descendentes cada nó tem, agrupando as linhas filhas com base na lista de ancestrais. Isso é útil para exibir a quantidade de itens ao lado dos nomes das categorias em um menu de navegação.
WITH RECURSIVE category_tree AS (
SELECT id, name, parent_id, id AS root_id
FROM categories
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id, ct.root_id
FROM categories c
JOIN category_tree ct ON ct.id = c.parent_id
)
SELECT
root_id,
COUNT(*) - 1 AS descendant_count
FROM category_tree
GROUP BY root_id
ORDER BY root_id;Verificação rápida
Teste sua compreensão das consultas recursivas para árvores de categorias.
Recapitulação da lição
Nesta lição, você aprendeu a percorrer uma tabela de categorias autorreferenciada usando WITH RECURSIVE.
Principais aprendizados:
- O membro âncora seleciona os nós iniciais (geralmente a raiz).
- O membro recursivo faz uma junção da CTE novamente com a tabela base para encontrar o próximo nível.
- Adicione uma coluna depth para acompanhar a quantidade de níveis de profundidade de cada nó.
- Construa uma cadeia de caracteres path para gerar trilhas de navegação.
- Percorra para cima seguindo parent_id no sentido inverso para encontrar todos os ancestrais.
- Use um vetor visited para evitar ciclos em dados inconsistentes.
Perguntas Frequentes
A aula “Percorrendo uma árvore de categorias” é grátis?
Sim — o texto completo de “Percorrendo uma árvore de categorias” é 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 SQL Academy, atualize para CoddyKit PRO. O curso de SQL Academy inclui 4 aulas no total.
O que vou aprender em “Percorrendo uma árvore de categorias”?
Expanda completamente as árvores de pai e filho. Você pratica SQL Academy 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 SQL Academy?
Nenhuma experiência prévia é necessária. SQL Academy 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 2 de 4.
Quanto tempo leva a aula “Percorrendo uma árvore de categorias”?
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 SQL Academy?
Sim. Cada aula de SQL Academy 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
- Como funcionam as CTEs recursivas
- Percorrendo uma árvore de categorias
- Gerando séries e sequências
- Evitando laços infinitos