database - tutorial - the django project
¿Cómo se interpreta sql with-recursive statement? (1)
No hay "recursión" aquí y creo que aquí es donde te confundes.
De la documentación de PostgreSQL: http://www.postgresql.org/docs/9.4/static/queries-with.html
Note: Strictly speaking, this process is iteration not recursion,
but RECURSIVE is the terminology chosen by the SQL standards committee.
Parafraseando esta oración, un WITH RECURSIVE
se puede ver como un simple bucle WHILE
.
WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 100
)
SELECT * FROM t;
Aquí hay un pseudocódigo hecho a medida para explicar este proceso en detalle
# Step 1: initialisation
LET cte_result = EMPTY
LET working_table = VALUES (1)
LET intermediate_table = EMPTY
# Step 2: result initialisation, merge initialisation into cte_result
cte_result = cte_result UNION working_table
# Step 3: iteration test
WHILE (working_table is not empty) DO
# Step 4: iteration select, we substitute the self-reference with working_table
intermediate_table = SELECT n+1 FROM working_table WHERE n < 100
# Step 5: iteration merge, merge the iteration result into cte_result
cte_result = cte_result UNION intermediate_table
# Step 6: iteration end, prepare for next iteration
working_table = intermediate_table
intermediate_table = EMPTY
END WHILE
# Step 7: return
RETURN cte_result
Y usando un ejemplo
# Step 1: initialisation
cte_result: EMPTY | working_table: 1 | intermediate_table: EMPTY
# Step 2: result initialisation
cte_result: 1 | working_table: 1 | intermediate_table: EMPTY
# Step 3: iteration test
count(working_table) = 1 # OK
# Step 4: iteration select
cte_result: 1 | working_table: 1 | intermediate_table: 2
# Step 5: iteration merge
cte_result: 1, 2 | working_table: 1 | intermediate_table: 2
# Step 6: iteration end
cte_result: 1, 2 | working_table: 2 | intermediate_table: EMPTY
# Step 3: iteration test
count(working_table) = 1 # OK
# Step 4: iteration select
cte_result: 1, 2 | working_table: 2 | intermediate_table: 3
# Step 5: iteration merge
cte_result: 1, 2, 3 | working_table: 2 | intermediate_table: 3
# Step 6: iteration end
cte_result: 1, 2, 3 | working_table: 3 | intermediate_table: EMPTY
# … 97 more iterations and you get this state
cte_result: 1, 2, …, 100 | working_table: 100 | intermediate_table: EMPTY
# Step 3: iteration test
count(working_table) = 1 # OK
# Step 4: iteration select, the iteration query does not return any rows due to the WHERE clause
cte_result: 1, 2, …, 100 | working_table: 100 | intermediate_table: EMPTY
# Step 5: iteration merge, nothing is merged into the cte_result
cte_result: 1, 2, …, 100 | working_table: 100 | intermediate_table: EMPTY
# Step 6: iteration end
cte_result: 1, 2, …, 100 | working_table: EMPTY | intermediate_table: EMPTY
# Step 3: iteration test
count(working_table) = 0 # STOP
# Step 7: return
cte_result: 1, 2, …, 100
Entonces, el resultado del CTE es todos los números del 1 al 100.
Me gustaría pedir ayuda para entender cómo funciona "con recursivo". Más precisamente, POR QUÉ la consulta de ancla (el término no recursivo) no se replica en la subllamada del CTE. Hice mi mejor esfuerzo para comprenderlo solo, pero no estoy seguro.
Antes que nada tomemos el ejemplo de PostgreSQL que es el más simple que encontré (haga la suma de 1 a 100):
WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 100)
SELECT sum(n) FROM t;
Mi código paso a paso (utilicé enlaces a continuación):
Evalúa el término no recursivo. Para la UNIÓN [...].
Incluya todas las filas restantes en el resultado de la consulta recursiva y también colóquelas en una tabla de trabajo temporal.
Siempre que la tabla de trabajo no esté vacía , repita estos pasos:
Evalúe el término recursivo, sustituyendo los contenidos actuales de la tabla de trabajo por la autorreferencia recursiva. Para la UNIÓN [...]. Incluya todas las filas restantes en el resultado de la consulta recursiva y también colóquelas en una tabla intermedia temporal.
Reemplace el contenido de la mesa de trabajo con el contenido de la mesa intermedia, luego vacíe la mesa intermedia ".
LVL 0:
parte no recursiva
- CTE: (N) 1
- TABLA DE TRABAJO: (N) 1
parte recursiva
- CTE: (N) 1
- TABLA DE TRABAJO: (N) 1
- TABLA INTERMEDIA (N) 2
(Esta es la parte en la que lío, creo) - sustitución de la TABLA DE TRABAJO
Entonces la t recursiva usará la TABLA DE TRABAJO para hacer SELECCIONAR n + 1 y colocar el resultado en TABLA INTERMEDIA.
UNION ALL
- CTE: (N) 1 2
- TABLA DE TRABAJO: (N) 2
- TABLA INTERMEDIA: LIMPIO
Luego pasamos al siguiente nivel por la llamada de t ¿verdad? (porque la condición END WHERE n <100 = FALSE)
LVL 1:
Sabemos que coz postgreSQL lo dice "Mientras la tabla de trabajo no esté vacía, repita los pasos recursivos" Entonces repetirá los pasos 2. y 3. (si estoy en lo correcto) hasta la condición END luego haga SUM.
PERO si me limito a seguir la llamada de la próxima letra de t, ¿no deberíamos hacer VALORES (1) primero?
Estoy realmente confundido acerca de cómo es posible.
Saludos cordiales, Falt4rm