복붙노트

[SQL] 어떻게 재귀 CTE는 라인으로 줄을 실행 하는가?

SQL

어떻게 재귀 CTE는 라인으로 줄을 실행 하는가?

나는 쓰기 하나에 이르기까지 충분히 재귀 CTE를의 형식을 가지고 생각하지만, 여전히 나 자신은 내가 수동으로 일합니다 (SQL 엔진을 자신하고 펜과 종이로 결과 집합에 도달 척) 처리 할 수 ​​있다는 것은 마지막에 좌절 찾기 . 나는 가까운 내가 무엇을 찾고에있는이를 찾았지만 충분히 설명하지했습니다. 나는 더는 C를 통해 추적 문제 ++ 순환 기능과 실행 방법을 이해가 없다 -하지만 SQL 내가 왜 또는 엔진이 정지 아는 방법을 이해하지 않습니다. 앵커 및 재귀 블록마다 호출되는, 또는 앵커 나중에 반복으로 건너 뜁니다합니까? (나는 그것을 의심하지만 난 그게 움직이지 것으로 보인다 방식에 대한 표현에 내 혼란을 시도하고있다.) 앵커가 때마다 호출되는 경우, 어떻게 최종 결과에서 여러 번 앵커 표시되지 않습니다? 나는 누군가가 단지 1 호선 2 호선 등 어떤 일이 어떤 결과 세트 늘어남에 따라 "메모리"입니다 다운 휴식을 할 수 있기를 바랍니다.

이해하기 쉬운 것으로 보인다 이후,이 페이지에서 내 예를 훔쳐의 자유를 촬영했습니다.

DECLARE @tbl TABLE ( 
      Id INT 
    , [Name] VARCHAR(20) 
    , ParentId INT 
) 

INSERT INTO @tbl( Id, Name, ParentId ) 
VALUES 
     (1, 'Europe', NULL) 
    ,(2, 'Asia',   NULL) 
    ,(3, 'Germany',   1) 
    ,(4, 'UK',        1) 
    ,(5, 'China',     2) 
    ,(6, 'India',     2) 
    ,(7, 'Scotland',  4) 
    ,(8, 'Edinburgh', 7) 
    ,(9, 'Leith',     8)  
; 

WITH abcd 
    AS ( 
        -- anchor 
        SELECT  id, Name, ParentID, 
                CAST(Name AS VARCHAR(1000)) AS Path 
        FROM    @tbl 
        WHERE   ParentId IS NULL 
        UNION ALL 
          --recursive member 
        SELECT  t.id, t.Name, t.ParentID, 
                CAST((a.path + '/' + t.Name) AS VARCHAR(1000)) AS "Path"
        FROM    @tbl AS t 
                JOIN abcd AS a 
                  ON t.ParentId = a.id 
       )
SELECT * FROM abcd 

해결법

  1. ==============================

    1.끝없는 UNION ALL의 같은 재귀 CTE의 생각 :

    끝없는 UNION ALL의 같은 재귀 CTE의 생각 :

    WITH    rows AS
            (
            SELECT  *
            FROM    mytable
            WHERE   anchor_condition
            ),
            rows2 AS
            (
            SELECT  *
            FROM    set_operation(mytable, rows)
            ),
            rows3 AS
            (
            SELECT  *
            FROM    set_operation(mytable, rows2)
            ),
            …
    SELECT  *
    FROM    rows
    UNION ALL
    SELECT  *
    FROM    rows2
    UNION ALL
    SELECT  *
    FROM    rows3
    UNION ALL
    …
    

    귀하의 경우에는, 그 것이다 :

    WITH    abcd1 AS
            ( 
            SELECT  *
            FROM    @tbl t
            WHERE   ParentId IS NULL 
            ),
            abcd2 AS
            ( 
            SELECT  t.*
            FROM    abcd1
            JOIN    @tbl t
            ON      t.ParentID = abcd1.id
            ),
            abcd3 AS
            ( 
            SELECT  t.*
            FROM    abcd2
            JOIN    @tbl t
            ON      t.ParentID = abcd2.id
            ),
            abcd4 AS
            ( 
            SELECT  t.*
            FROM    abcd3
            JOIN    @tbl t
            ON      t.ParentID = abcd3.id
            ),
            abcd5 AS
            ( 
            SELECT  t.*
            FROM    abcd4
            JOIN    @tbl t
            ON      t.ParentID = abcd4.id
            ),
            abcd6 AS
            ( 
            SELECT  t.*
            FROM    abcd5
            JOIN    @tbl t
            ON      t.ParentID = abcd5.id
            )
    SELECT  *
    FROM    abcd1
    UNION ALL
    SELECT  *
    FROM    abcd2
    UNION ALL
    SELECT  *
    FROM    abcd3
    UNION ALL
    SELECT  *
    FROM    abcd4
    UNION ALL
    SELECT  *
    FROM    abcd5
    UNION ALL
    SELECT  *
    FROM    abcd6
    

    abcd6 수익률 결과가 없습니다 때문에, 이것은 정지 상태를 의미한다.

    이론적으로, 재귀 CTE가 무한이 될 수 있지만, 실제적으로, SQL Server는 무한 레코드로 이어질 것 쿼리를 금지하려고합니다.

    이 문서를 읽을 수 있습니다 :

  2. ==============================

    2.CTE 사용인지 알고리즘 :

    CTE 사용인지 알고리즘 :

    예를 취할 수 있습니다 :

    WITH    cte ( value )
              AS (
                   SELECT   1
                   UNION ALL
                   SELECT   value + 1
                   FROM     cte
                   WHERE    value < 4
                 )
        SELECT  *
        FROM    cte
    

    이 쿼리의 결과는 다음과 같습니다

    value
    -----------
    1
    2
    3
    4
    
    (4 row(s) affected)
    

    의 단계에 의해 단계를 살펴 보자 :

    Execute anchor query (SELECT 1), we got:
      r0 = 1
      cte = r0 = 1
    
        |
        |
        V
    
    Now we execute
    SELECT value + 1 FROM cte WHERE value < 4
    Since cte is r0 (only has 1), we got:
      r1 = 2
      cte = r1 = 2
    
        |
        |
        V
    
    Now we execute
    SELECT value + 1 FROM cte WHERE value < 4
    Since cte is r1 (only has 2), we got:
      r2 = 3
      cte = r2 = 3
    
        |
        |
        V
    
    Now we execute
    SELECT value + 1 FROM cte WHERE value < 4
    Since cte is r2 (only has 3), we got:
      r3 = 4
      cte = r3 = 4
    
        |
        |
        V
    
    Now we execute
    SELECT value + 1 FROM cte WHERE value < 4
    Since cte is r3 (only has 4), we got:
      r4 = NULL (because r3 (4) is equal to 4, not less than 4)
    Now we stop the recursion!
    
        |
        |
        V
    
    Let's calculate the final result:
    R = r0 union all
        r1 union all
        r2 union all
        r3 union all
      = 1 union all
        2 union all
        3 union all
        4 union all
      = 1
        2
        3
        4
    
  3. ==============================

    3.나는 다음과 같은 고장 생각 :

    나는 다음과 같은 고장 생각 :

    이 페이지는 아마 가장 잘 설명합니다. 그것은 CTE의 실행 경로 단계별 연습을 갖는다.

  4. ==============================

    4.당신은 아마이 링크를하고자했다. 아니, 앵커가 실행되지 않고 여러 번 (그 다음 노동 조합 모두가 모든 결과에 나타난 요구, 수 없습니다). 이전 링크에서 세부 사항.

    당신은 아마이 링크를하고자했다. 아니, 앵커가 실행되지 않고 여러 번 (그 다음 노동 조합 모두가 모든 결과에 나타난 요구, 수 없습니다). 이전 링크에서 세부 사항.

  5. ==============================

    5.1 단계:

    1 단계:

    1 Europe NULL Europe
    2 Asia   NULL Asia
    

    2 단계:

    1 Europe  NULL Europe
    2 Asia    NULL Asia
    3 Germany 1    Europe/Germany
    4 UK      1    Europe/UK
    5 China   2    Asia/China
    6 India   2    Asia/India
    

    3 단계 :

    1 Europe   NULL Europe
    2 Asia     NULL Asia
    3 Germany  1    Europe/Germany
    4 UK       1    Europe/UK
    5 China    2    Asia/China
    6 India    2    Asia/India
    7 Scotland 4    Europe/UK/Scotland
    

    4 단계 :

    1 Europe    NULL Europe
    2 Asia      NULL Asia
    3 Germany   1    Europe/Germany
    4 UK        1    Europe/UK
    5 China     2    Asia/China
    6 India     2    Asia/India
    7 Scotland  4    Europe/UK/Scotland
    8 Edinburgh 7    Europe/UK/Scotland/Edinburgh
    

    5 단계 :

    1 Europe    NULL Europe                             0
    2 Asia      NULL Asia                               0
    3 Germany   1    Europe/Germany                     1
    4 UK        1    Europe/UK                          1
    5 China     2    Asia/China                         1
    6 India     2    Asia/India                         1
    7 Scotland  4    Europe/UK/Scotland                 2
    8 Edinburgh 7    Europe/UK/Scotland/Edinburgh       3
    9 Leith     8    Europe/UK/Scotland/Edinburgh/Leith 4
    

    5 단계에서 마지막 열은 수준이다. 각 단계 동안 행은 이미 무엇인지에 대한 추가됩니다. 도움이 되었기를 바랍니다.

  6. from https://stackoverflow.com/questions/3187850/how-does-a-recursive-cte-run-line-by-line by cc-by-sa and MIT license