如何在单个查询中获取类似(父 - 子)映射列的链表?

时间:2013-04-24 10:41:11

标签: sql sql-server sql-server-2008 tsql recursive-query

考虑下表

+--------+-------+--+
| Parent | Child |  |
+--------+-------+--+
|      1 |     2 |  |
|     10 |    13 |  |
|      2 |     3 |  |
|      3 |     4 |  |
|     13 |    14 |  |
|      4 |     5 |  |
|     15 |    16 |  |
|      5 |     1 |  |
+--------+-------+--+

在此表中,我遵循父子的层次结构。从这张表我想得到一个结果如下表

+--------+-------+--+
| Parent | Child |  |
+--------+-------+--+
|      1 |     2 |  |
|      2 |     3 |  |
|      3 |     4 |  |
|      4 |     5 |  |
|      5 |     1 |  |
+--------+-------+--+

我希望在代码(1-2-3-4-5-1)中获得层次结构。目前我正在询问每个孩子的父母(有时,孩子可以是任何以前的父母,如5-1 )。对于长层次结构,它将执行许多查询。我怎样才能提高效率呢?

3 个答案:

答案 0 :(得分:4)

;with cte(parent,child) as (
    select parent, child
      from sometable
     where parent = 1  --- seed
     UNION ALL
    select t.parent, t.child
      from sometable t
      join cte on cte.child = t.parent
)
    select *
      from cte;

为避免无限循环,您必须存储遍历的ID列表:

;with cte(parent,child,traversed) as (
    select parent, child, ',' + right(parent,10) + ','
      from sometable
     where parent = 1  --- seed
     UNION ALL
    select t.parent, t.child, cte.traversed + right(t.parent,10) + ','
      from sometable t
      join cte on cte.child = t.parent
     where not cte.traversed like ',%' + t.parent + '%,'
)
    select parent, child
      from cte;

但由于必须进行LIKE检查,因此它不能快速地运行。

答案 1 :(得分:2)

请尝试:

DECLARE @table as TABLE(Parent int, Child int)

insert into @table values
(1, 2),
(10, 13),
(2, 3),
(3, 4),
(13, 14),
(4, 5),
(5, 1)

select * from @table

declare @ParentID int
set @ParentID=1

;WITH T(Parent, Child)AS
    ( 
        SELECT Parent, Child from @table where Parent=@ParentID
        UNION ALL
        SELECT T1.Parent, T1.Child FROM @table T1 INNER JOIN T ON T1.Parent=T.Child
        WHERE T.Child<>@ParentID

    )
select * from T
order by Parent

答案 2 :(得分:-1)

本手册涵盖:http://msdn.microsoft.com/en-us/library/ms186243(v=sql.105).aspx 所以不应该习惯于在手册中提出已经有好答案的问题。