El síntoma: la primera consulta funciona y la segunda no encuentra la CTE
PostgreSQL describe las CTE como tablas temporales que existen solo para una consulta. MySQL define una CTE como un resultado temporal con alcance de una única sentencia. SQLite las describe como vistas temporales que existen durante una sola sentencia SQL.
Por tanto, WITH no crea un objeto persistente que puedas reutilizar en la siguiente sentencia independiente.
Ejemplo: intentar reutilizar el nombre después del punto y coma
WITH clientes_activos AS (
SELECT id, nombre
FROM clientes
WHERE activo = 1
)
SELECT *
FROM clientes_activos;
SELECT COUNT(*)
FROM clientes_activos;La primera sentencia puede usar clientes_activos. Cuando termina en el punto y coma, esa CTE deja de formar parte del alcance. La segunda sentencia necesita definirla de nuevo o consultar otro objeto real.
Si necesitas varios resultados dentro de una sola sentencia, reutiliza la CTE allí
Una misma CTE puede referenciarse varias veces dentro de la sentencia que la contiene. Por ejemplo, puedes compararla consigo misma, usarla en subconsultas o basar otras CTE en ella.
WITH clientes_activos AS (
SELECT id, nombre
FROM clientes
WHERE activo = 1
)
SELECT
(SELECT COUNT(*) FROM clientes_activos) AS total,
(SELECT MIN(id) FROM clientes_activos) AS primer_id;Si necesitas reutilización entre sentencias, elige otro mecanismo
La solución depende de la intención:
- Repetir la lógica en pocas consultas: vuelve a declarar la CTE.
- Compartir una consulta estable: considera una vista.
- Guardar resultados intermedios durante una sesión o proceso: una tabla temporal puede ser más adecuada, con sintaxis y ciclo de vida específicos del motor.
- Persistir datos: usa una tabla normal si realmente forman parte del modelo.
No conviertas automáticamente una CTE en tabla permanente: primero decide si quieres reutilizar una definición o almacenar datos.
Puedes encadenar varias CTE dentro del mismo WITH
WITH clientes_activos AS (
SELECT id, nombre
FROM clientes
WHERE activo = 1
),
primeros AS (
SELECT id, nombre
FROM clientes_activos
WHERE id <= 100
)
SELECT *
FROM primeros;Las CTE comparten la sentencia y pueden formar una secuencia legible de transformaciones.
Método de diagnóstico
- Busca el punto y coma que termina la sentencia con
WITH. - Comprueba si el error aparece después de ese límite.
- Decide si necesitas otra consulta o persistencia real.
- Si todo pertenece a una única tarea, considera mantenerlo en una sola sentencia con varias CTE.
- Si el resultado debe vivir más tiempo, usa una vista o tabla según el caso.
Error frecuente: pensar que WITH equivale a CREATE VIEW
Una CTE nombra un resultado dentro de una sentencia
CREATE VIEW crea un objeto de esquema que puede consultarse más tarde. WITH introduce nombres auxiliares para la sentencia actual. Son herramientas relacionadas en legibilidad, pero tienen ciclos de vida distintos.
Práctica correctiva
Obtén dos métricas sin salir del alcance
Define una CTE pedidos_pagados con los pedidos cuyo estado sea 'pagado'. En una sola sentencia devuelve el número de pedidos y el importe máximo.
Solución razonada
WITH pedidos_pagados AS (
SELECT id, total
FROM pedidos
WHERE estado = 'pagado'
)
SELECT COUNT(*) AS cantidad,
MAX(total) AS mayor_total
FROM pedidos_pagados;La CTE existe durante toda esa sentencia y puede alimentar ambas agregaciones.
Qué debes recordar
- Una CTE tiene alcance de una sola sentencia SQL.
- El punto y coma marca el final de ese alcance.
- Puedes referenciar una CTE varias veces dentro de la misma sentencia.
- Para reutilización posterior, evalúa una vista o una tabla según la necesidad.
Conceptos relacionados
Fuentes técnicas
La sintaxis y las diferencias de motor de esta guía se contrastaron con documentación primaria: