traverse query

  • I need a query to get Parent, childrens,grand childrens,greatgrand childrens etc relationship upto nth level (data i have is more than 100th level.)

    Here is sample data..

    Table:parentmaster

    ID Name

    ---- ----------

    8571 File/sam

    5475 Folder/Pat

    6808 path/test

    7591 file/test2

    4485 Pr/dsn/

    Table:Tree

    Parent child

    ------ ------

    8571 5475

    8571 6808

    8571 7591

    5475 4485

    Expected output

    Table:Treedesc

    Parent child Parentchildtree

    ------ ----- ----------------

    8571 5475 File/sam-->Folder/Pat

    8571 6808 File/sam-->path/test

    8571 7591 File/sam-->file/test2

    5475 4485 File/sam-->Folder/Pat-->Pr/dsn/

    Thanks for your help in advance

  • Maybe this will help?

    Displaying Sorted Hierarchies[/url]

  • Thanks for the response. This was helpful but my database has 2 tables where the provided the link has a single table which has all the names, ids in single table.

    I was not getting the expected output..

  • Mvs2k11 (3/5/2016)


    Thanks for the response. This was helpful but my database has 2 tables where the provided the link has a single table which has all the names, ids in single table.

    I was not getting the expected output..

    So in your case, you will need to change the recursive CTE from using a single table to using a join between the two tables. The anchor part would just join the tree table and the other table to ind the "root" nodes; the recursive part would join the CTE itself to the tree to find the next step, and join that again to the other table to find the description, which then should also be concatenated to the description from the CTE.

    If you understand how the recursive CTE works, and you understand how a normal joins works, you should be able to solve this.

    If you need further help, then please post the tabbles used (as CREATE TABLE statements), a small but illustrative selection of sample data (as INSERT statements), the expected results for that sample data, and the work you already done so far - then we can look at where yoou are stuck and help you get over that bump.


    Hugo Kornelis, SQL Server/Data Platform MVP (2006-2016)
    Visit my SQL Server blog: https://sqlserverfast.com/blog/
    SQL Server Execution Plan Reference: https://sqlserverfast.com/epr/

  • Here is the query...

    CREATE TABLE #Treedesc

    (

    ID BIGINT NOT NULL,

    Name Varchar(500) NOT NULL,

    CONSTRAINT PK_Tree

    PRIMARY KEY CLUSTERED ID)

    );

    INSERT INTO #Treedesc

    (ID, Name)

    SELECT 8571, 'File/sam' UNION ALL

    SELECT 5475, 'Folder/Pat'UNION ALL

    SELECT 6808, 'path/test'UNION ALL

    SELECT 7591, 'file/test2'UNION ALL

    SELECT 4485, 'Pr/dsn/'

    ;

    CREATE TABLE #Tree

    (

    ParentID BIGINT NOT NULL,

    ChildID INT NULL,

    CONSTRAINT PK_Tree

    PRIMARY KEY CLUSTERED ParentID,ChildID)

    );

    INSERT INTO #Tree

    (ParentID, ChildID)

    SELECT 8571, 5475 UNION ALL

    SELECT 8571, 6808 UNION ALL

    SELECT 8571, 7591 UNION ALL

    SELECT 5475, 4485

    ;

    WITH

    cteHierarchy AS

    (

    --Get the top level

    SELECT c.ChildID, a.ParentID, b.Name, Level = 1,

    HierarchicalPath = CAST('-->'+CAST(Name AS VARCHAR(500)) AS VARCHAR(4000))

    FROM #Tree a inner join #Treedesc b on a.ParentID = b.ID

    inner join #Treedesc c on a.childID = c.ID

    UNION ALL

    --Get the recursive level

    SELECT e.ChildID, e.ParentID, e.Name, Level = d.Level + 1,

    HierarchicalPath = CAST(d.HierarchicalPath + '-->'+CAST(e.Name AS VARCHAR(500)) AS VARCHAR(4000))

    FROM #Tree e

    INNER JOIN cteHierarchy d ON e.ParentID = d.ChildID

    )

    SELECT ChildID, ,

    ParentID ,

    Name = SPACE((Level-1)*4) + Name,

    Level,

    HierarchicalPath

    FROM cteHierarchy

    ORDER BY HierarchicalPath

  • I had to do some fixing to your CREATE TABLE scripts (suggestion - next time when you post a question, test the scripts first). And I changed the data types of the IDs to all be int, becuase mixing bigint and int for columns that reference each other is a bad idea. I did not add a foreign key between the tables, but I suggest that you do.

    I then modified the CTE code to return the data you requested:

    CREATE TABLE #Treedesc

    (

    ID INT NOT NULL,

    Name Varchar(500) NOT NULL,

    CONSTRAINT PK_TreeDesc

    PRIMARY KEY CLUSTERED (ID)

    );

    INSERT INTO #Treedesc

    (ID, Name)

    SELECT 8571, 'File/sam' UNION ALL

    SELECT 5475, 'Folder/Pat'UNION ALL

    SELECT 6808, 'path/test'UNION ALL

    SELECT 7591, 'file/test2'UNION ALL

    SELECT 4485, 'Pr/dsn/'

    ;

    CREATE TABLE #Tree

    (

    ParentID INT NOT NULL,

    ChildID INT NOT NULL,

    CONSTRAINT PK_Tree

    PRIMARY KEY CLUSTERED (ParentID,ChildID)

    );

    INSERT INTO #Tree

    (ParentID, ChildID)

    SELECT 8571, 5475 UNION ALL

    SELECT 8571, 6808 UNION ALL

    SELECT 8571, 7591 UNION ALL

    SELECT 5475, 4485

    ;

    WITH cteHierarchy

    AS (-- Anchor query: root level with all its children

    SELECT c.ParentID AS Parent, c.ChildID AS Child, CAST(r.Name + '-->' + cD.Name AS varchar(MAX)) AS ParentChildTree

    FROM #Treedesc AS r -- root

    INNER JOIN #Tree AS c -- children

    ON c.ParentID = r.ID

    INNER JOIN #Treedesc AS cD -- children's description

    ON cD.ID = c.ChildID

    WHERE NOT EXISTS -- verify it's a root: no ascendants

    (SELECT *

    FROM #Tree AS a -- ascendant

    WHERE a.ChildID = r.ID)

    -- Recursive part: children of previously added nodes

    UNION ALL

    SELECT c.ParentID, c.ChildID, p.ParentChildTree + '-->' + cD.Name

    FROM cteHierarchy AS p -- parent

    INNER JOIN #Tree AS c -- children

    ON c.ParentID = p.Child

    INNER JOIN #Treedesc AS cD -- children's description

    ON cD.ID = c.ChildID)

    SELECT * FROM cteHierarchy;

    I have added some comments, to help you understand how the process works. I hope that with this, you'll be able to maintain the code in the future.


    Hugo Kornelis, SQL Server/Data Platform MVP (2006-2016)
    Visit my SQL Server blog: https://sqlserverfast.com/blog/
    SQL Server Execution Plan Reference: https://sqlserverfast.com/epr/

  • Thanks a lot..

    The provided query works fine however when I ran the query against with 1 million records which is failing due to maximum recursion error and I have added option (maxrecursion 32767) but still faliing..

    Error:the statement terminated..The maximum recursion has been exhausted before the statement completion.

    Please help..

  • Mvs2k11 (3/5/2016)


    Thanks a lot..

    The provided query works fine however when I ran the query against with 1 million records which is failing due to maximum recursion error and I have added option (maxrecursion 32767) but still faliing..

    Error:the statement terminated..The maximum recursion has been exhausted before the statement completion.

    Please help..

    https://msdn.microsoft.com/en-us/library/ms181714.aspx

    "When 0 is specified, no limit is applied."


    Hugo Kornelis, SQL Server/Data Platform MVP (2006-2016)
    Visit my SQL Server blog: https://sqlserverfast.com/blog/
    SQL Server Execution Plan Reference: https://sqlserverfast.com/epr/

  • Thanks a lot Hugo Kornelis

    However i have ran against the database whenever verified after the results it has lot of duplicate records showing in the result set..

    Can you help please..

  • Please post a repro script. Not with millions of lines - try to create a repro script that is as small as possible, yet shows the same problem you are seeing.


    Hugo Kornelis, SQL Server/Data Platform MVP (2006-2016)
    Visit my SQL Server blog: https://sqlserverfast.com/blog/
    SQL Server Execution Plan Reference: https://sqlserverfast.com/epr/

  • This is a case where you can run into a infinite loop if you had something like

    PARENT CHILD

    -------- -------

    1 2

    2 3

    3 1

    You end up with 1 --> 2 -->3 -->1 -->2 and so on. This is why the max recursion protection is there so I would not necessarily override it unless you are certain you dont have this situation in your data.

    ----------------------------------------------------

  • Thanks ..I was figuring out the data which has millions of records however I have the data which have mentioned..

    What is the solution.. when I put max recursion to 0 which was processing for long and I had to cancel the query..

    Please suggest..

  • Mvs2k11 (3/8/2016)


    Thanks ..I was figuring out the data which has millions of records however I have the data which have mentioned..

    What is the solution.. when I put max recursion to 0 which was processing for long and I had to cancel the query..

    Please suggest..

    Solution is easy - check a child record you're about to add has already been added before.

    Stop looping if such record already exists.

    Using Hugo's script:

    -- Recursive part: children of previously added nodes

    UNION ALL

    SELECT c.ParentID, c.ChildID, p.ParentChildTree + '-->' + cD.Name

    FROM cteHierarchy AS p -- parent

    INNER JOIN #Tree AS c -- children

    ON c.ParentID = p.Child

    INNER JOIN #Treedesc AS cD -- children's description

    ON cD.ID = c.ChildID)

    WHERE NOT EXISTS (select * from cteHierarchy AS e

    where e.Child = c.ChildID)

    _____________
    Code for TallyGenerator

  • Thanks Sergiy !

    I have tried to modify the change you mentioned but I got an error..

    Msg 253, Level 16, State 1, Line 1

    Recursive member of a common table expression 'cteHierarchy' has multiple recursive references.

    Please suggest

  • Sergiy (3/8/2016)


    Mvs2k11 (3/8/2016)


    Thanks ..I was figuring out the data which has millions of records however I have the data which have mentioned..

    What is the solution.. when I put max recursion to 0 which was processing for long and I had to cancel the query..

    Please suggest..

    Solution is easy - check a child record you're about to add has already been added before.

    Stop looping if such record already exists.

    Using Hugo's script:

    -- Recursive part: children of previously added nodes

    UNION ALL

    SELECT c.ParentID, c.ChildID, p.ParentChildTree + '-->' + cD.Name

    FROM cteHierarchy AS p -- parent

    INNER JOIN #Tree AS c -- children

    ON c.ParentID = p.Child

    INNER JOIN #Treedesc AS cD -- children's description

    ON cD.ID = c.ChildID)

    WHERE NOT EXISTS (select * from cteHierarchy AS e

    where e.Child = c.ChildID)

    THis code will not work. Did you check this before posting? I dont think you can reference the CTE more than once in the recursion portion.

    ----------------------------------------------------

Viewing 15 posts - 1 through 15 (of 17 total)

You must be logged in to reply to this topic. Login to reply