如何解释sql with-recursive语句?

Fal*_*4rm 5 database postgresql recursion recursive-query with-statement

我想请教一些关于理解"递归"如何工作的帮助.更确切地说,为什么锚查询(非递归项)不会复制到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;
Run Code Online (Sandbox Code Playgroud)

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

  1. 评估非递归术语.对于UNION [...].

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

  2. 只要工作表不为空,请重复以下步骤:

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

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

LVL 0:

  1. 非递归部分

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

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

(这是我想的那部分) - 取代WORKING TABLE

因此递归t将使用WORKING TABLE来执行SELECT n + 1并将结果放在INTERMEDIATE TABLE中.

  1. UNION ALL

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

LVL 1:

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

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

我真的很困惑它是如何可能的.

最好的问候,Falt4rm

Clé*_*ost 6

这里没有"递归",我认为这是你感到困惑的地方.

从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.
Run Code Online (Sandbox Code Playgroud)

为了解释这句话,WITH RECURSIVE可以将a视为一个简单的WHILE循环.

WITH RECURSIVE t(n) AS (
  VALUES (1)
  UNION ALL
  SELECT n+1 FROM t WHERE n < 100
)
SELECT * FROM t;
Run Code Online (Sandbox Code Playgroud)

这里有一些定制的伪代码来详细解释这个过程

# 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
Run Code Online (Sandbox Code Playgroud)

并举例说明

# 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
Run Code Online (Sandbox Code Playgroud)

因此,CTE的结果是从1到100的所有数字.

  • 非常感谢您的回答(并花时间发布这篇巨大的帖子)。对于这个问题我真的理清了思路。&lt;3 (2认同)