Contenido de esta guía
Respuesta rápida
Una CTE recursiva permite que una consulta construya filas nuevas a partir de las filas que la propia CTE ya ha producido. Se utiliza para recorrer jerarquías, árboles, relaciones padre-hijo o secuencias cuya profundidad no conoces de antemano.
El patrón habitual tiene dos partes: un caso inicial que aporta las primeras filas y una parte recursiva que encuentra el siguiente nivel. La recursión termina cuando esa segunda parte deja de producir filas.
El modelo mental: raíz → siguiente nivel → repetir
Una CTE ordinaria nombra un resultado intermedio. Una CTE recursiva añade una relación consigo misma para avanzar por niveles. En un organigrama, por ejemplo, puedes empezar por la persona sin responsable, buscar después a quienes dependen de ella y repetir el proceso con cada nuevo nivel.
filas iniciales
↓
filas del siguiente nivel
↓
filas del siguiente nivel
↓
... hasta que no aparezcan filas nuevasLa palabra RECURSIVE hace visible esa intención. PostgreSQL y SQLite documentan este patrón dentro de la cláusula WITH.
Estructura de WITH RECURSIVE
WITH RECURSIVE nombre_cte AS (
-- Caso inicial
SELECT ...
UNION ALL
-- Paso recursivo
SELECT ...
FROM tabla
JOIN nombre_cte ON ...
)
SELECT ...
FROM nombre_cte;Lee las dos ramas por separado. La primera define desde dónde empieza el recorrido. La segunda expresa cómo encontrar filas relacionadas con las que ya están en la CTE. UNION ALL reúne ambos conjuntos sin eliminar duplicados automáticamente.
La condición de avance es parte de la corrección. Una recursión sin una forma real de terminar puede repetir trabajo, alcanzar límites del motor o producir un recorrido incorrecto. En datos jerárquicos reales también debes pensar qué ocurriría ante un ciclo.
Ejemplo: recorrer el organigrama de empleados
La base educativa ya contiene empleados.responsable_id. Carmen no tiene responsable; Alex, Carlos y Gonzalo dependen de Carmen; y a partir de ellos aparecen niveles posteriores.
WITH RECURSIVE organigrama AS (
SELECT id,
nombre,
responsable_id,
0 AS nivel,
nombre AS ruta
FROM empleados
WHERE responsable_id IS NULL
UNION ALL
SELECT e.id,
e.nombre,
e.responsable_id,
o.nivel + 1,
o.ruta || ' > ' || e.nombre
FROM empleados AS e
JOIN organigrama AS o
ON e.responsable_id = o.id
)
SELECT nombre, nivel, ruta
FROM organigrama
ORDER BY ruta;| nombre | nivel | ruta |
|---|---|---|
| Carmen Soler | 0 | Carmen Soler |
| Alex Ramos | 1 | Carmen Soler > Alex Ramos |
| Bea Molina | 2 | Carmen Soler > Alex Ramos > Bea Molina |
| Ismael Díaz | 2 | Carmen Soler > Alex Ramos > Ismael Díaz |
| Carlos Peña | 1 | Carmen Soler > Carlos Peña |
| Diana León | 2 | Carmen Soler > Carlos Peña > Diana León |
| Ernesto Cano | 2 | Carmen Soler > Carlos Peña > Ernesto Cano |
| Fátima Ríos | 2 | Carmen Soler > Carlos Peña > Fátima Ríos |
| Gonzalo Nieto | 1 | Carmen Soler > Gonzalo Nieto |
| Helena Costa | 2 | Carmen Soler > Gonzalo Nieto > Helena Costa |
El caso inicial produce solo a Carmen. La rama recursiva usa cada fila obtenida para encontrar empleados cuyo responsable_id coincide con ese id. nivel + 1 registra la profundidad y ruta permite ver por qué camino se llegó a cada persona.
UNION ALL no significa “recursión infinita”
UNION ALL es habitual porque no obliga a deduplicar cada iteración. Pero la terminación no depende de cambiarlo mecánicamente por UNION: depende de que el paso recursivo tenga una relación que finalmente deje de producir filas y de que los datos no creen recorridos cíclicos no controlados.
En una jerarquía bien formada, una clave como responsable_id avanza hacia descendientes y llega a hojas que ya no tienen personas a su cargo. En grafos generales, la prevención de ciclos exige una estrategia explícita y puede variar según el motor y el problema.
Errores frecuentes
No separar el caso inicial del paso recursivo
Si no puedes explicar qué filas aparecen antes de la primera repetición, la consulta es difícil de verificar. Ejecuta mentalmente primero la rama inicial y después una sola iteración de la recursiva.
Unir en la dirección equivocada
Para bajar por un organigrama, la fila hija debe apuntar al identificador de la fila ya encontrada: e.responsable_id = o.id. Invertir esa relación cambia el sentido del recorrido.
Confundir el orden del recorrido con el orden del resultado
La recursión decide qué filas se generan. La presentación final sigue necesitando un ORDER BY si quieres un orden predecible.
Práctica guiada
Obtén solo el equipo que depende de Carlos Peña
Construye una CTE recursiva que empiece por el empleado con id = 4 y devuelva a Carlos y todos sus descendientes. Muestra nombre y nivel, donde Carlos está en nivel 0.
Criterio de éxito: aparecen Carlos Peña, Diana León, Ernesto Cano y Fátima Ríos.
WHERE id = 4.id en la CTE aunque no lo muestres al final: lo necesitas para relacionar el siguiente nivel.e.responsable_id = equipo.id.Solución razonada
WITH RECURSIVE equipo AS (
SELECT id, nombre, 0 AS nivel
FROM empleados
WHERE id = 4
UNION ALL
SELECT e.id,
e.nombre,
equipo.nivel + 1
FROM empleados AS e
JOIN equipo
ON e.responsable_id = equipo.id
)
SELECT nombre, nivel
FROM equipo
ORDER BY nivel, nombre;El ancla fija a Carlos. La rama recursiva encuentra únicamente filas que tienen como responsable a alguien ya incluido, por lo que el recorrido queda limitado a ese subárbol.
Compatibilidad y límites
PostgreSQL y SQLite documentan CTE recursivas mediante WITH RECURSIVE. Las reglas de búsqueda, detección de ciclos, límites de recursión y optimización no son idénticas entre motores, así que una consulta de producción debe comprobarse en el motor concreto.
El motor educativo integrado de AprenderSQL.es enseña y ejecuta CTE ordinarias, pero no simula CTE recursivas. Los resultados de esta página se comprobaron con SQLite real sobre los mismos datos educativos, no con el laboratorio del curso.
Qué debes recordar
- Una CTE recursiva combina un caso inicial con un paso que referencia la propia CTE.
- La recursión termina cuando el paso recursivo deja de producir filas.
- Las jerarquías padre-hijo son un caso de uso natural.
- Los ciclos y la dirección de la relación deben tratarse explícitamente.
- El orden final requiere
ORDER BYsi debe ser predecible.