Al llegar a SQL desde otros lenguajes de programación, la estructura de una consulta recursiva parece bastante extraña. Camine a través de él paso a paso, y parece desmoronarse.
Considere el siguiente ejemplo sencillo:
CREATE TABLE #NUMS
(N BIGINT);
INSERT INTO #NUMS
VALUES (3), (5), (7);
WITH R AS
(
SELECT N FROM #NUMS
UNION ALL
SELECT N*N AS N FROM R WHERE N*N < 10000000
)
SELECT N FROM R ORDER BY N;
Vamos a atravesarlo.
Primero, el miembro ancla se ejecuta y el conjunto de resultados se coloca en R. Por lo tanto, R se inicializa en {3, 5, 7}.
Luego, la ejecución cae por debajo de UNION ALL y el miembro recursivo se ejecuta por primera vez. Se ejecuta en R (es decir, en la R que actualmente tenemos en la mano: {3, 5, 7}). Esto da como resultado {9, 25, 49}.
¿Qué hace con este nuevo resultado? ¿Anexa {9, 25, 49} a los {3, 5, 7} existentes, etiqueta la unión R resultante y luego continúa con la recursividad desde allí? ¿O redefine R para que sea solo este nuevo resultado {9, 25, 49} y haga toda la unión más tarde?
Ninguna elección tiene sentido.
Si R ahora es {3, 5, 7, 9, 25, 49} y ejecutamos la próxima iteración de la recursión, entonces terminaremos con {9, 25, 49, 81, 625, 2401} y hemos perdido {3, 5, 7}.
Si R ahora es solo {9, 25, 49}, entonces tenemos un problema de etiquetado incorrecto. Se entiende que R es la unión del conjunto de resultados del miembro ancla y todos los conjuntos de resultados del miembro recursivo subsiguientes. Mientras que {9, 25, 49} es solo un componente de R. No es la R completa que hemos acumulado hasta ahora. Por lo tanto, escribir el miembro recursivo como selección de R no tiene sentido.
Ciertamente aprecio lo que @Max Vernon y @Michael S. han detallado a continuación. Es decir, que (1) todos los componentes se crean hasta el límite de recursión o conjunto nulo, y luego (2) todos los componentes se unen entre sí. Así es como entiendo que la recursividad de SQL realmente funcione.
Si estuviéramos rediseñando SQL, tal vez impondríamos una sintaxis más clara y explícita, algo como esto:
WITH R AS
(
SELECT N
INTO R[0]
FROM #NUMS
UNION ALL
SELECT N*N AS N
INTO R[K+1]
FROM R[K]
WHERE N*N < 10000000
)
SELECT N FROM R ORDER BY N;
Algo así como una prueba inductiva en matemáticas.
El problema con la recursividad de SQL tal como está actualmente es que está escrito de manera confusa. La forma en que está escrito dice que cada componente se forma seleccionando desde R, pero no significa la R completa que ha sido (o parece haber sido) construida hasta ahora. Solo significa el componente anterior.