sql with-recursive 语句如何解释?
How sql with-recursive statement interpreted?
我想请求帮助了解 "with recursive" 的工作原理。
更准确地说,为什么锚查询(非递归项)没有复制到 CTE 的子调用中。我一个人尽力去理解,但我不确定。
首先让我们以 PostgreSQL 为例,这是我找到的最简单的例子(求和 1 到 100):
WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 100)
SELECT sum(n) FROM t;
我的代码演练(我使用了下面的链接):
计算非递归项。对于联合 [...]。
在递归查询的结果中包含所有剩余的行,并将它们放在临时工作table.
只要工作table不为空,重复这些步骤:
计算递归项,用当前工作内容table代替递归自引用。对于UNION [... ].
在递归查询的结果中包含所有剩余的行,并将它们放在临时中间 table.
将工作table的内容替换为中间table的内容,然后清空中间table。
LVL 0 :
非递归部分
- 热膨胀系数:(N) 1
- 正在工作 TABLE : (N) 1
递归部分
- 热膨胀系数:(N) 1
- 正在工作 TABLE : (N) 1
- 中级 TABLE (N) 2
(我认为这是我搞砸的部分)- 替换 WORKING TABLE
因此递归 t 将使用 WORKING TABLE 执行 SELECT n+1 并将结果放入 INTERMEDIATE TABLE.
联合所有
- 热膨胀系数:(N) 1 2
- 正在工作 TABLE : (N) 2
- 中级 TABLE:清洁
那我们就通过t的调用进入下一个lvl吧?
(因为 END 条件 WHERE n < 100 = FALSE)
等级 1:
我们知道因为 postgreSQL 这么说 "So long as the working table is not empty, repeat the recursive steps"
因此它将重复步骤 2. 和 3.(如果我是正确的)直到 END 条件然后执行 SUM。
但是如果我只是演练 t 的下一个 lvl 的调用,我们不应该先执行 VALUES(1) 吗?
我真的很困惑这怎么可能。
此致,
Falt4rm
这里没有 "recursion" 发生,我认为这就是你感到困惑的地方。
来自 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.
换句话说,WITH RECURSIVE
可以看作是一个简单的 WHILE
循环。
WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 100
)
SELECT * FROM t;
这里有一些定制的伪代码来详细解释这个过程
# 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
并使用示例
# 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
所以 CTE 的结果是从 1 到 100 的所有数字。
我想请求帮助了解 "with recursive" 的工作原理。 更准确地说,为什么锚查询(非递归项)没有复制到 CTE 的子调用中。我一个人尽力去理解,但我不确定。
首先让我们以 PostgreSQL 为例,这是我找到的最简单的例子(求和 1 到 100):
WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 100)
SELECT sum(n) FROM t;
我的代码演练(我使用了下面的链接):
计算非递归项。对于联合 [...]。
在递归查询的结果中包含所有剩余的行,并将它们放在临时工作table.
只要工作table不为空,重复这些步骤:
计算递归项,用当前工作内容table代替递归自引用。对于UNION [... ]. 在递归查询的结果中包含所有剩余的行,并将它们放在临时中间 table.
将工作table的内容替换为中间table的内容,然后清空中间table。
LVL 0 :
非递归部分
- 热膨胀系数:(N) 1
- 正在工作 TABLE : (N) 1
递归部分
- 热膨胀系数:(N) 1
- 正在工作 TABLE : (N) 1
- 中级 TABLE (N) 2
(我认为这是我搞砸的部分)- 替换 WORKING TABLE
因此递归 t 将使用 WORKING TABLE 执行 SELECT n+1 并将结果放入 INTERMEDIATE TABLE.
联合所有
- 热膨胀系数:(N) 1 2
- 正在工作 TABLE : (N) 2
- 中级 TABLE:清洁
那我们就通过t的调用进入下一个lvl吧? (因为 END 条件 WHERE n < 100 = FALSE)
等级 1:
我们知道因为 postgreSQL 这么说 "So long as the working table is not empty, repeat the recursive steps" 因此它将重复步骤 2. 和 3.(如果我是正确的)直到 END 条件然后执行 SUM。
但是如果我只是演练 t 的下一个 lvl 的调用,我们不应该先执行 VALUES(1) 吗?
我真的很困惑这怎么可能。
此致, Falt4rm
这里没有 "recursion" 发生,我认为这就是你感到困惑的地方。
来自 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.
换句话说,WITH RECURSIVE
可以看作是一个简单的 WHILE
循环。
WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 100
)
SELECT * FROM t;
这里有一些定制的伪代码来详细解释这个过程
# 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
并使用示例
# 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
所以 CTE 的结果是从 1 到 100 的所有数字。