views:

199

answers:

1

I am trying to write a recursive CTE query in SQL Server 2005 but am getting an odd set of results. My table is:

PairID  ChildID ParentID
900        1        2       
901        2        3       
902        3        4       

This is my CTE Query:

WITH TESTER (PairID, 
             ChildID, 
             ParentID, 
             Level)
AS (SELECT a.PairID, a.ChildID,a.ParentID, 0 AS Level
    FROM BusinessHierarchy AS a
    UNION ALL
    SELECT b.PairID, b.ChildID, b.ParentID, oh.Level + 1 AS Level
    FROM BusinessHierarchy AS b INNER JOIN
    TESTER AS oh ON b.ChildID =  oh.ParentID)
SELECT 
      x.PairID, 
      x.ChildID,
      x.ParentID,
      x.Level
 FROM TESTER AS x
 ORDER BY x.Level, x.ChildID, x.ParentID

Ok, so I am now getting a dataset return, however, it is not as expected in that it contains repetition in the following manner:

PairID  ChildID ParentID Level
900     1       2        0
901     2       3        0
902     3       4        0
...

900     2       3        1
901     3       4        1
...

900     3       4        2

If someone could explain to me why this is happening and how I would could correct it I would be very grateful.

As far as my last question goes, how would I have to modify it to display the initial childID with each of the parents like this:

Original
PairID  ChildID ParentID Level
900     1       2        0
901     2       3        1
902     3       4        2

I want it displayed as:
PairID  ChildID ParentID Level
900     1       2        0
901     1       3        1
902     1       4        2
+1  A: 

Your problem is your starting point. The first part of the CTE query returns all rows (notice their level is all 0).

Then - Your next part of the query will go and get all the related rows (which adds to your earlier resultset).

I did notice, however, that you have no record for the id of 4

if you did, here is what you would do:

;WITH TESTER (PairID, ChildID, ParentID, Level) AS (
    SELECT
        a.PairID,
        a.ChildID,
        a.ParentID,
        0 AS Level
    FROM BusinessHierarchy AS a
    LEFT JOIN BusinessHierarchy a2 ON a.ParentID = a2.ChildID
    WHERE a2.PairID is null

    UNION ALL

    SELECT
        b.PairID,
        b.ChildID,
        b.ParentID,
        oh.Level + 1 AS Level
    FROM BusinessHierarchy AS b
    INNER JOIN TESTER AS oh ON b.ParentID =  oh.ChildID
)

SELECT 
    x.PairID, 
    x.ChildID,
    x.ParentID,
    x.Level
FROM TESTER AS x
ORDER BY x.Level, x.ChildID, x.ParentID

Also, see my answer to a similar question to show the correct sort order (using the path)

Gabriel McAdams
I ran the query but get no results. I think the problem is the 'parentId is null' which is why I emitted it from my version. I have read several forums and versions/examples and just don't see why this doesn't work.
flavour404
my code assumed that you would add a record with an id of 4. If you're not, you have to have a starting point some other way.
Gabriel McAdams
See my modified answer that will work in your case (I joined back to the table to see where there was no child record).
Gabriel McAdams
Is @tbl supposed to be BusinessHierarchy again? @tbl throws an error and BusinessHierarchy returns the wrong data. @tbl is a temporary table isn't it? Is there another way of achieving this?I also ran some test data with a record for 4 with null as the parent and now I see what you mean in that it worked perfectly.
flavour404
Yeah. Sorry. cut and paste error. @tbl should be BusinessHierarchy.
Gabriel McAdams
Must declare variable "@tbl" incorrect syntax near ')'.
flavour404
@flavour: That was a paste error. I modified my answer already.
Gabriel McAdams
Ok, that is great but I am going to ask a couple of daft questions. 1) How do I change the level assignment around so that the lowest level starts at 0 and the highest level is, in this exmaple 2? 2) How do you group them together, so for example lets say that I wanted to put in childID = 1 (or 90937) and I would have the hierarchy for that group displayed?Thanks, this has really been a great help.
flavour404
1) by changing your starting point (the first part of the CTE query). for example, "where childid = 1" and then modify the join to get parent instead of child. - 2) modify the where clause so that you're using a variable (like "where childid = @variable")
Gabriel McAdams
Don't forget to accept this answer if it was useful.
Gabriel McAdams
OK, one final question, how do you display the lowest level child ID rather than the subsequent higher up ones? I put an example of what I mean at the top, but lets just say that my first child id is 1, that child id would be displayed as the childID for each level?
flavour404
I actually managed to achieve everything I wanted with this, including reversing the levels and also the childID display. I wouldn't have been able to do it without your guidance, so thanks, it was great.
flavour404
Not a problem. I'm glad I was able to help.
Gabriel McAdams