queryLab · software_de_entrenamiento en espera
Nivel 4 · Avanzado · SQL · avanzado

[SQL 13] CTE y consultas recursivas

WITH para escribir consultas por pasos; WITH RECURSIVE para jerarquías y series.
0 / 6 retos resueltos 📘 SQL COMANDOS · CTE (Common Table Expression)
Al terminar esta práctica podrás…
  • Dividir una consulta compleja en pasos con nombre usando WITH.
  • Encadenar varias CTE y reutilizarlas en la consulta final.
  • Recorrer jerarquías (organigrama jefe → empleado) con WITH RECURSIVE.
  • Generar series (números, meses) para completar informes con ceros.

Una CTE (Common Table Expression) es un resultado temporal con nombre que existe solo durante la consulta. Se declara con WITH nombre AS (SELECT …) y luego se usa como una tabla. Hace lo mismo que una tabla derivada, pero se lee de arriba hacia abajo, paso a paso, y se puede reutilizar.

Una CTE recursiva se llama a sí misma. Tiene dos partes unidas por UNION ALL:

  1. el caso base (punto de partida, por ejemplo el presidente), y
  2. el paso recursivo, que se une con la propia CTE para avanzar un nivel (sus subordinados).

El motor repite el paso recursivo hasta que no aparecen filas nuevas. Es la forma estándar de recorrer jerarquías, árboles y grafos (en Oracle también existe CONNECT BY).

Sintaxis
WITH paso1 AS (SELECT …),
     paso2 AS (SELECT … FROM paso1 …)
SELECT … FROM paso2;

WITH RECURSIVE arbol(id, nivel) AS (
  SELECT id, 1 FROM t WHERE padre IS NULL      -- caso base
  UNION ALL
  SELECT t.id, a.nivel + 1                      -- paso recursivo
  FROM t JOIN arbol a ON t.padre = a.id
)
SELECT * FROM arbol;
WITH
Define resultados intermedios con nombre.
Varias CTE
Se separan con comas; una puede usar a las anteriores.
WITH RECURSIVE
Caso base UNION ALL paso recursivo.
Condición de término
La recursión para cuando el paso no produce filas nuevas (o con un WHERE n < 12).
Jerarquías
Organigramas, categorías, rutas: e.manager_id = arbol.id.
Series
Generar 1..12 para incluir meses sin datos con un LEFT JOIN.
SQLite / PostgreSQL / MySQL 8
WITH RECURSIVE …
Oracle
WITH … (sin RECURSIVE) · o CONNECT BY PRIOR employee_id = manager_id

1 · Ejemplos guiados · ejecuta y modifica cada bloque

01CTE simple
Primero calculamos el promedio por departamento; luego lo unimos con los empleados para ver quién lo supera.
sql-cte.sql
Presiona «ejecutar» para ver el resultado.
02Varias CTE encadenadas
Paso 1: dotación por departamento. Paso 2: le agregamos el nombre. Final: solo los grandes.
sql-cte.sql
Presiona «ejecutar» para ver el resultado.
03Serie de números
La recursión más simple: del 1 al 10.
sql-cte.sql
Presiona «ejecutar» para ver el resultado.
04Organigrama completo
Desde el presidente (sin jefe) bajamos nivel por nivel, construyendo la ruta de mando.
sql-cte.sql
Presiona «ejecutar» para ver el resultado.
05Cadena de mando hacia arriba
El recorrido inverso: desde un empleado (199) subimos hasta el presidente.
sql-cte.sql
Presiona «ejecutar» para ver el resultado.
06Completar meses sin datos
Generamos los 12 meses y hacemos LEFT JOIN con las contrataciones de 2021: los meses sin contrataciones aparecen con 0.
sql-cte.sql
Presiona «ejecutar» para ver el resultado.

⚠ Errores frecuentes

  • Olvidar la condición de término en una serie (WHERE n < 10): la recursión no termina.
  • Usar UNION en vez de UNION ALL en la recursión: además de más lento, puede ocultar filas legítimas repetidas.
  • Poner el JOIN al revés en el paso recursivo: para bajar es e.manager_id = arbol.employee_id; para subir, m.employee_id = cadena.manager_id.
  • En Oracle no se escribe la palabra RECURSIVE (y en versiones antiguas se usa CONNECT BY).

2 · Retos con corrección automática

Escribe tu solución y pulsa comprobar (Ctrl + Enter). Tu consulta y la solución se ejecutan en bases limpias y se comparan los resultados: no importan los nombres de las columnas, sí los datos (y el orden, cuando el reto lo pide). Si te atascas, usa la pista o mira el resultado esperado.

3 · Preguntas tipo solemne

1. ¿Qué partes tiene una CTE recursiva?
2. ¿Qué ventaja tiene una CTE frente a una subconsulta en el FROM?
3. En Oracle, ¿qué cláusula clásica recorre jerarquías?