【问题标题】:How sql with-recursive statement interpreted?sql with-recursive 语句如何解释?
【发布时间】:2016-06-20 02:59:11
【问题描述】:

我想请教一些关于“使用递归”如何工作的帮助。 更准确地说,为什么锚查询(非递归项)不会复制到 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;

我的代码演练(我使用下面的链接):

  1. 计算非递归项。对于联合 [...]。

    在递归查询的结果中包含所有剩余的行,并将它们放在临时工作表中。

  2. 只要工作表不是空的,重复这些步骤:

    • 评估递归项,用工作表的当前内容替换递归自引用。 对于 UNION [...]。 在递归查询的结果中包含所有剩余的行,并将它们放在一个临时中间表中。

    • 用中间表的内容替换工作表的内容,然后清空中间表。”

LVL 0:

  1. 非递归部分

    • CTE : (N) 1
    • 工作表:(N) 1
  2. 递归部分

    • CTE : (N) 1
    • 工作表:(N) 1
    • 中间表 (N) 2

(我认为这是我乱七八糟的部分)-替换工作表

所以递归的 t 将使用 WORKING TABLE 来做 SELECT n+1 并将结果放入 INTERMEDIATE TABLE。

  1. 联合所有

    • CTE : (N) 1 2
    • 工作表:(N) 2
    • 中间表:已清理
  2. 然后我们通过 t 的调用进入下一个 lvl 对吧? (因为 END 条件 WHERE n

LVL 1:

我们知道因为 postgreSQL 说“只要工作表不为空,重复递归步骤” 所以它会重复第 2 步和第 3 步(如果我是正确的)直到 END 条件然后执行 SUM。

但是,如果我只是演练 t 的下一个 lvl 的调用,我们不应该先执行 VALUES(1) 吗?

我真的很困惑这怎么可能。

最好的问候, Falt4rm

【问题讨论】:

  • 天哪……什么东西收敛什么东西。
  • 为我回答下一个 lvl - 仍然无法解决这个递归 lvl +1 跳过锚启动的想法。

标签: database postgresql recursion recursive-query with-statement


【解决方案1】:

这里没有发生“递归”,我认为这就是你感到困惑的地方。

来自 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 的所有数字。

【讨论】:

  • 非常感谢这个答案(并花时间发布这个巨大的帖子)。对于这个问题,我真的很清楚。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-18
  • 2019-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-09
  • 1970-01-01
相关资源
最近更新 更多