Section 4.7. Traversing Hierarchies Recursively

   

4.7 Traversing Hierarchies Recursively

4.7.1 Problem

You need to step through a hierarchy and print out a report listing all vertices. You want the report to show the hierarchical nature of the data by indenting children under their parent node.

4.7.2 Solution

One solution is to use a recursive algorithm to traverse the tree. To do that, encapsulate the algorithm in a stored procedure. The following code creates a stored procedure named TraversProjectsRecursive. The stored procedure takes one argument, specifying from which node to begin. The procedure then works its way down through that node's children, grandchildren, and so forth.

 CREATE PROCEDURE TraverseProjectsRecursive @VertexId INTEGER AS    /* to change action on each vertex, change these lines */    DECLARE @Name VARCHAR(20)    SELECT @Name=(SELECT Name                      FROM Projects WHERE VertexId=@VertexId)     PRINT SPACE(@@NESTLEVEL*2)+STR(@VertexId)+' '+@Name    /* ****** */    DECLARE subprojects CURSOR LOCAL FOR       SELECT VertexId FROM Projects WHERE Parent=@VertexId          OPEN subprojects       FETCH NEXT FROM subprojects INTO @VertexId       WHILE @@FETCH_STATUS=0 BEGIN          EXEC TraverseProjectsRecursive @VertexId          FETCH NEXT FROM subprojects INTO @VertexId       END    CLOSE subprojects    DEALLOCATE subprojects 

When calling the procedure, you need to specify the initial node from which you want the procedure to start traversing. If you want to print out the entire hierarchy, then specify the root node (in our case 1). For example:

 TraverseProjectsRecursive 1    1 New SW    2 Specifications      3 Interviews      4 Drafts      5 Consolidations      6 Final document        7 Presentation    8 Prototype      9 UI Design      10 Calculations        11 Correctness Testing      12 Database    13 Development      14 UI Implementation      15 Coding      16 Inital testing    17 Beta testing      18 Final adjustments    19 Production testing 

4.7.3 Discussion

The algorithm used by the TraverseProjectsRecursive procedure is a classical tree-traversal method adapted to the specifics of SQL. You can easily adapt this procedure for use with other hierarchical structures besides the projects structure shown in this chapter. To adapt this procedure, change only the SELECT and PRINT statements.

When you create a recursive procedure such as the one shown here, MS SQL Server will warn you with a message such as the following: "Cannot add rows to sysdepends for the current stored procedure because it depends on the missing object 'TraverseProjectsRecursive.' The stored procedure will still be created.'' Do not worry about this message. Recursive procedures are a special case, and you can safely ignore the warning.

The first SELECT statement in the procedure retrieves the name associated with the vertex that is passed in as a parameter. That name is placed into the @Name variable, which is then used in the subsequent PRINT statement:

 PRINT SPACE(@@NESTLEVEL*2)+STR(@VertexId)+' '+@Name 

In this PRINT statement, we use the @@NESTLEVEL variable. That variable is maintained automatically by SQL Server and returns the current nesting level. This information is a great advantage when working with stored procedures. In our case, we want to indent every project proportionally to its depth. To do that, we multiply the nesting level by two to indent each child two spaces underneath its parent.

After we print the name of the current vertex, we need to go forward to its children. A vertex can have more than one child, so we define a cursor to select these:

 DECLARE subprojects CURSOR LOCAL FOR    SELECT VertexId FROM Projects WHERE Parent=@VertexId 

This cursor definition uses the LOCAL clause, ensuring that the cursor is defined for the current procedure only. By default, cursors are global, which means that any cursor defined is visible from all code executed within the current connection. Since this procedure calls itself repeatedly within the context of one connection, we must specify that this cursor definition be local to each invocation of the procedure.

After opening the subprojects cursor, we simply step through the list of subprojects and recursively invoke the TraverseProjectsRecursive procedure on each one:

 FETCH NEXT FROM subprojects INTO @VertexId    WHILE @@FETCH_STATUS=0 BEGIN       EXEC TraverseProjectsRecursive @VertexId       FETCH NEXT FROM subprojects INTO @VertexId    END 

Even though the recursive mechanisms are very elegant, they are not very efficient. Furthermore, in SQL Server they have a limit of only 32 nesting levels. If you query your hierarchy infrequently, then the overhead of recursion may be acceptable, and you need not bother with other mechanisms. However, if you do this type of thing often, some further optimizations might be necessary to give you adequate performance. Sometimes it's useful to use recursion for prototyping, because recursive solutions are simple to code. Later, you can optimize your code with a nonrecursive solution before you go to production.

   


Transact-SQL Cookbook
Transact-SQL Cookbook
ISBN: 1565927567
EAN: 2147483647
Year: 2005
Pages: 152

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net