How sql with-recursive statement interpreted?

后端 未结 1 1970
时光说笑
时光说笑 2021-01-05 13:42

I would like to ask get some help about understanding how \"with recursive\" works. More precisely WHY the anchor query (the non-recursive term) isn\'t repl

相关标签:
1条回答
  • 2021-01-05 13:45

    There is no "recursion" taking place here and I think that this is where you get confused.

    From the PostgreSQL documentation: 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.
    

    To paraphrase this sentence, a WITH RECURSIVE can be viewed as a simple WHILE loop.

    WITH RECURSIVE t(n) AS (
      VALUES (1)
      UNION ALL
      SELECT n+1 FROM t WHERE n < 100
    )
    SELECT * FROM t;
    

    Here is some custom-made pseudo-code to explain this process in detail

    # 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
    

    And using an example

    # 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
    

    So the result of the CTE is all numbers from 1 to 100.

    0 讨论(0)
提交回复
热议问题