如何解释sql with-recursive语句?

时间:2015-05-03 15:46:15

标签: 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;

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

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

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

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

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

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

  3. LVL 0:

    1. 非递归部分

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

      • CTE:(N)1
      • 工作表:(N)1
      • 中间表(N)2
    3. (这是我认为的那个部分) - 取代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&lt; 100 = FALSE)

      3. LVL 1:

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

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

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

        祝你好运, Falt4rm

1 个答案:

答案 0 :(得分:6)

没有&#34;递归&#34;发生在这里,我认为这是你感到困惑的地方。

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