views:

37

answers:

2

My Table 'Levels' in a SQL Server 2005 database looks like this:

LevelId Description      ParentLevelId
0       Level_1          NULL
1       Level_2          0
2       Level_3          0
3       Level_4          1
4       Level_5          3

I now want to create a query that will produce a results set in which every level and all of its children, grand-children etc. are returned. So basically I want to return an output like this:

LevelId Description DescendantId Descendant_Description
0       Level_1     0            Level_1
0       Level_1     1            Level_2
0       Level_1     2            Level_3    
0       Level_1     3            Level_4   
0       Level_1     4            Level_5    
1       Level_2     1            Level_2
1       Level_2     3            Level_3
1       Level_2     4            Level_5
2       Level_3     2            Level_3
3       Level_4     3            Level_4
4       Level_5     4            Level_5 

Oddly enough I wrote a similar query today where all levels and all of its ancestors are shown. Somehow I'm stuck writing a similar query for something which is 'the other way around'. Anyone any ideas?

A: 

The easiest way is to write a recursive CTE. Read this article for more details: Common Table Expressions

Giorgi
Thanks Giorgio. I know that this is the easiest way. I already wrote one returning all the ancestors of a level. The reason why I asked this question was that I'm stuck now with writing a query that returns me all levels and then all the descendants of each level
trabart
+2  A: 
WITH    q (LevelId, Description, DescendantId, Descendant_Description) AS
        (
        SELECT  LevelId, Description, LevelId, Description
        FROM    mytable
        UNION ALL
        SELECT  t.LevelId, t.Description, q.DescendantId, q.Descendant_Description
        FROM    q
        JOIN    mytable t
        ON      t.ParentLevelId = q.LevelId
        )
SELECT  *
FROM    q
ORDER BY
        LevelId, DescendantId

Since this query returns all ancestor-descendant pairs in the system (builds a such called transitive closure), all you need to put it the other way round is to swap the fields and change the ordering:

WITH    q (LevelId, Description, DescendantId, Descendant_Description) AS
        (
        SELECT  LevelId, Description, LevelId, Description
        FROM    mytable
        UNION ALL
        SELECT  t.LevelId, t.Description, q.DescendantId, q.Descendant_Description
        FROM    q
        JOIN    mytable t
        ON      t.ParentLevelId = q.LevelId
        )
SELECT  DescendantId AS LevelId, Descendant_Description AS Description,
        LevelId AS DescendantId, Description AS Descendant_Description
FROM    q
ORDER BY
        LevelId, DescendantId
Quassnoi
Piece o' cake, eh?
Denis Valeev
@Denis: of course.
Quassnoi
Quassnoi, this query returns me all levels and the ancestors of each level. This is the query that I already figured out myself. I want to have a query that returns all levels and the descendants of each level.
trabart
@trabart: this query returns all ancestor-descendant pairs. The resultset you want only differs in ordering. See the post update.
Quassnoi
@Quassnoi: Piece o'cake, eh? :) Thx!
trabart