Recorrido de un árbol de categorías
Expanda por completo los árboles de padre e hijo
Recorrido de un árbol de categorías es una lección gratuita de SQL Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de SQL Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de SQL Academy incluye 4 lecciones en total.
¿Qué es un árbol de categorías?
Muchos conjuntos de datos del mundo real tienen una relación padre-hijo. Un catálogo de productos puede incluir categorías como Electrónica → Teléfonos → Smartphones. Cada nodo tiene un padre, lo que forma una estructura de árbol.
En SQL, esto suele almacenarse como una tabla que se referencia a sí misma: cada fila tiene un id y un parent_id que apunta a otra fila de la misma tabla.
CREATE TABLE categories (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
parent_id INT REFERENCES categories(id)
);Datos de ejemplo de categorías
Rellenemos un pequeño árbol de categorías. El nodo raíz tiene parent_id = NULL porque no tiene padre. Todos los demás nodos apuntan a su padre mediante un parent_id que no es 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);El problema de las consultas simples
Un SELECT simple solo puede obtener un nivel cada vez. Para llegar a tres niveles de profundidad necesitaría tres consultas independientes o tres autouniones, lo que se vuelve inmanejable a medida que crece el árbol.
WITH RECURSIVE resuelve este problema al permitir que una consulta haga referencia a su propia salida y recorra los niveles uno a uno hasta que no se encuentren nuevas filas.
-- This only shows direct children of Electronics (level 1)
SELECT id, name
FROM categories
WHERE parent_id = 1;Anatomía de WITH RECURSIVE
Una CTE recursiva tiene dos partes separadas por UNION ALL:
1. Miembro ancla — un SELECT normal que proporciona las filas iniciales.
2. Miembro recursivo — un SELECT que vuelve a unir la CTE consigo misma y produce el siguiente nivel en cada iteración.
El motor repite el miembro recursivo hasta que este devuelve cero filas.
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;Recorrer todo el árbol desde la raíz
Comience en la raíz (donde parent_id IS NULL) y descienda hasta cada uno de sus descendientes. El miembro recursivo vuelve a unir cada fila acumulada con categories mediante la relación entre padres e hijos.
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;Seguir la ruta
Es útil registrar la ruta completa desde la raíz hasta cada nodo. Puede construir una cadena path concatenando los nombres de los ancestros a medida que profundiza en la recursión.
Así resulta sencillo mostrar rutas de navegación como Electrónica / Teléfonos / 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;Comenzar desde un nodo específico
No tiene que comenzar en la raíz. Al cambiar la cláusula WHERE del ancla, puede recorrer el subárbol de cualquier nodo. Aquí comenzamos desde Teléfonos (id = 2) y obtenemos todos sus descendientes.
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;Recorrer hacia arriba: encontrar todos los ancestros
También puede recorrer el árbol en sentido inverso: hacia arriba, desde una hoja hasta la raíz. Solo tiene que invertir la unión para seguir parent_id hacia arriba en lugar de hacia abajo. Esto resulta útil cuando necesita la ruta de navegación completa de un nodo hoja conocido.
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;Añadir una vista con sangría
Un patrón habitual de la interfaz de usuario consiste en aplicar sangría visual a los nodos hijos. Puede utilizar REPEAT (o LPAD) junto con la columna depth para anteponer espacios a cada nombre y producir una vista de árbol basada en 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;Evitar los bucles infinitos
Si los datos contienen un ciclo (A es padre de B y B es padre de A), la recursión se ejecutará indefinidamente y provocará un error. Puede evitarlo registrando los identificadores visitados en un array y deteniéndose cuando el identificador actual ya esté 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;Contar los descendientes de cada nodo
Una vez que tiene el árbol completo, puede agregar sus datos. Aquí contamos cuántos descendientes tiene cada nodo agrupando las filas hijas con respecto a la lista de ancestros. Esto resulta útil para mostrar el número de elementos junto a los nombres de las categorías en un menú de navegación.
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;Comprobación rápida
Compruebe su comprensión de las consultas recursivas para árboles de categorías.
Resumen de la lección
En esta lección ha aprendido a recorrer una tabla de categorías autorreferenciada mediante WITH RECURSIVE.
Conceptos clave:
- El miembro ancla selecciona los nodos iniciales (normalmente, la raíz).
- El miembro recursivo vuelve a unir la CTE con la tabla base para encontrar el siguiente nivel.
- Añada una columna depth para registrar a qué profundidad se encuentra cada nodo.
- Construya una cadena path para generar rutas de navegación.
- Recorra el árbol hacia arriba siguiendo parent_id en sentido inverso para encontrar todos los ancestros.
- Utilice un array visited para protegerse frente a ciclos en datos con problemas.
Preguntas frecuentes
¿La lección «Recorrido de un árbol de categorías» es gratis?
Sí — el texto completo de «Recorrido de un árbol de categorías» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de SQL Academy, actualiza a CoddyKit PRO. El curso de SQL Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Recorrido de un árbol de categorías»?
Expanda por completo los árboles de padre e hijo Practicas SQL Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar SQL Academy?
No se requiere experiencia previa. SQL Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Recorrido de un árbol de categorías»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de SQL Academy?
Sí. Cada lección de SQL Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Cómo funcionan las CTE recursivas
- Recorrido de un árbol de categorías
- Generación de series y secuencias
- Cómo evitar bucles infinitos