The following code extract is fully described as well has how recursion works in my blog article: http://sqlblogcasts.com/blogs/tonyrogerson/archive/2008/05/11/common-table-expressions-cte-s-how-it-works-how-recursion-works-using-with-adjacency-list.aspx
create table adjacency_list (
parent_extractedword_id int not null,
child_extractedword_id int not null,
constraint pk_adjacency_list primary key clustered( parent_extractedword_id, child_extractedword_id )
)
create table extractedword (
id int not null constraint pk_extractedword primary key clustered,
word varchar(50) not null
)
insert extractedword( id, word ) values( 11, 'demo' )
insert extractedword( id, word ) values( 12, 'on' )
insert extractedword( id, word ) values( 13, 'cte' )
insert extractedword( id, word ) values( 14, 'recursion' )
insert extractedword( id, word ) values( 21, 'does' )
insert extractedword( id, word ) values( 22, 'this' )
insert extractedword( id, word ) values( 23, 'rock' )
insert extractedword( id, word ) values( 24, 'ya' )
insert extractedword( id, word ) values( 25, 'boat?' )
insert adjacency_list ( parent_extractedword_id, child_extractedword_id ) values( 11, 12 )
insert adjacency_list ( parent_extractedword_id, child_extractedword_id ) values( 12, 13 )
insert adjacency_list ( parent_extractedword_id, child_extractedword_id ) values( 13, 14 )
insert adjacency_list ( parent_extractedword_id, child_extractedword_id ) values( 21, 22 )
insert adjacency_list ( parent_extractedword_id, child_extractedword_id ) values( 22, 23 )
insert adjacency_list ( parent_extractedword_id, child_extractedword_id ) values( 23, 24 )
insert adjacency_list ( parent_extractedword_id, child_extractedword_id ) values( 24, 25 )
; WITH WordStruct( org_parent_id, child_id, recurse_depth )
AS (
-- The anchor is the starting point for possible recursion
SELECT org_parent_id = parent_extractedword_id,
child_id = child_extractedword_id,
recurse_depth = CAST( 0 as tinyint )
FROM adjacency_list l1
WHERE NOT EXISTS ( SELECT * -- The Anchor should only contain root PARENT's
FROM adjacency_list l2
WHERE l2.child_extractedword_id = l1.parent_extractedword_id )
-- Recursive Member
UNION ALL
SELECT org_parent_id = l1.child_id,
child_id = l2.child_extractedword_id,
recurse_depth = recurse_depth + cast( 1 as tinyint )
FROM WordStruct l1
INNER JOIN adjacency_list l2 on l2.parent_extractedword_id = l1.child_id
)
select e.id, e.word, ws.*,
case when org_parent_id=e.id then 'ROOT' else 'CHILD.DEPTH=' + CAST( recurse_depth + 1 as varchar(5) ) end
from WordStruct ws
INNER JOIN extractedword e on e.id = ws.child_id
or ( ws.recurse_depth = 0 -- Do this to get the desc for the root parent
and e.id = ws.org_parent_id )
order by ws.org_parent_id, ws.child_id