SQL Server: How to limit CTE recursion to rows just recursivly added?

前端 未结 8 1057
北海茫月
北海茫月 2020-12-08 23:12

Simpler Example

Let\'s try a simpler example, so people can wrap their heads around the concepts, and have a practical example that you can copy&paste into SQL

相关标签:
8条回答
  • 2020-12-08 23:48

    The issue is with the Sql Server default recursion limit (100). If you try your example at the top with the anchor restriction removed (also added Order By):

    WITH NodeChildren AS
    (
       --initialization
       SELECT ParentNodeID, NodeID, 1 AS GenerationsRemoved
       FROM Nodes
    
       UNION ALL
    
       --recursive execution
       SELECT P.ParentNodeID, N.NodeID, P.GenerationsRemoved + 1
       FROM NodeChildren AS P
          inner JOIN Nodes AS N
          ON P.NodeID = N.ParentNodeID
    )
    SELECT ParentNodeID, NodeID, GenerationsRemoved
    FROM NodeChildren
    ORDER BY ParentNodeID ASC
    

    This produces the desired results. The problem you aare facing is with a larger number of rows you will recirse over 100 times which is a default limit. This can be changed by adding option (max recursion x) after your query, where x is a number between 1 and 32767. x can also be set to 0 which sets no limit however could very quickly have a very detrimental impact on your server performance. Clearly as the number of rows in Nodes increases, the number of recursions will can rise very quickly and I would avoid this approach unless there was a known upper limit on the rows in the table. For completeness, the final query should look like:

     WITH NodeChildren AS
        (
           --initialization
           SELECT ParentNodeID, NodeID, 1 AS GenerationsRemoved
           FROM Nodes
    
           UNION ALL
    
           --recursive execution
           SELECT P.ParentNodeID, N.NodeID, P.GenerationsRemoved + 1
           FROM NodeChildren AS P
              inner JOIN Nodes AS N
              ON P.NodeID = N.ParentNodeID
        )
        SELECT * 
        FROM NodeChildren
        ORDER BY ParentNodeID
        OPTION (MAXRECURSION 32767)
    

    Where 32767 could be adjusted downwards to fit your scenario

    0 讨论(0)
  • 2020-12-08 23:52

    Try this:

    WITH Nodes AS
    (
       --initialization
       SELECT ParentNodeID, NodeID, 1 AS GenerationsRemoved
       FROM ##Nodes
    
       UNION ALL
    
       ----recursive execution
       SELECT P.ParentNodeID, N.NodeID, P.GenerationsRemoved + 1
       FROM Nodes AS P
          INNER JOIN ##Nodes AS N
          ON P.NodeID = N.ParentNodeID
       WHERE P.GenerationsRemoved <= 10
    
    )
    SELECT ParentNodeID, NodeID, GenerationsRemoved
    FROM Nodes
    ORDER BY ParentNodeID, NodeID, GenerationsRemoved
    

    Basically removing the "only show me absolute parents" from the initialization query; That way it generates the results starting from each of them and decending from there. I also added in the "WHERE P.GenerationsRemoved <= 10" as an infinite recursion catch(replace 10 with any number up to 100 to fit your needs). Then add the sort so it looks like the results you wanted.

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