简体   繁体   中英

T-SQL Recursive CTE to find Highest ParentID

Yesterday's Interview I was asked a interesting question that how to find the highest ParentID for each row.

I couldn't answer this question that time, but I found the solution online but I still cannot understand how this query works...

Can anyone explain to me how Recursive CTE works in detail? Thanks

I post the sample question and solution I come up with at the button

=================================================================

Create table dbo.##Test001 (ID int, Name varchar(100), ParentID int)

Insert into ##Test001 values (1, 'AA', null), (2, 'BB', 1), (3, 'CC', 2), (4, 'DD', 3)
,(5, 'AAA', null), (6, 'BBB', 5), (7, 'CCC', 6), (8, 'DDD', 7)



;WITH c AS (
SELECT id, parentid, id AS topParentID FROM   ##Test001 
WHERE  ParentID is null 

UNION ALL 

SELECT T.id, T.parentid, c.topparentid FROM   ##Test001 AS T 
INNER JOIN c 
ON T.parentid = c.id 
WHERE  T.id <> T.parentid
) 
SELECT id, topparentid FROM  c 
ORDER  BY id 

It might help to remind yourself about recursion using a function.

-- pseudo code
void numberFunction(int i) {

  Print i

  increment i

  if(i<10) {
    numberFunction(i);
  }
}

Or, even better a math function that you can do by hand.

Fact (n) = n * fact (n-1) for n > 0

The structure of the recursive common table expression (CTE) is:

  • Anchor query (which serves as input to recursive query)
  • UNION ALL
  • Recursive query - stop when recursive query returns empty set

Notice in the math/pseudo code function, we either increment or decrement a variable and check for the exit state.

In this query the increment / decrement functionality is in the recursive query when T.id is returned for the matched T.parentid

The exit state for this query is when the recursive query returns an empty set.

WITH c AS 
(
    SELECT 
        id, parentid, id AS topParentID 
    FROM   
        #Test001 
    WHERE  
        ParentID is null 

    UNION ALL 

    SELECT 
        T.id, T.parentid, c.topparentid 
    FROM   
        #Test001 AS T 
    INNER JOIN
        c ON T.parentid = c.id 
    WHERE  
        T.id <> T.parentid
) 
SELECT id, topparentid 
FROM c 
ORDER BY id

The output of the anchor establishes the topmost parent and serves as the the input to the recursive query.

id  parentid    topParentID
1   NULL        1
5   NULL        5

This output is then joined with the temp table #Test001 T on T.parentid = c.id.

ID  Name    ParentID
1   AA  NULL
2   BB  1
3   CC  2
4   DD  3
5   AAA NULL
6   BBB 5
7   CCC 6
8   DDD 7

SELECT T.id, T.parentid, c.topparentid 
FROM #Test001 AS T 
INNER JOIN c ON T.parentid = c.id 

T.id    T.parentid     c.topparentid
2       1              1
6       5              5

You can continue the process for the remaining id/parent id combinations.

UNION ALL combines all the results of both the anchor query and all recursive queries. UNION ALL can be used with queries with same number of parameters and similar types.

Source: Recursive Queries Using CTE

Assembly Recursion

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM