在SQL 2005中从递归查询结果排序层次结构

时间:2009-02-11 22:31:12

标签: sql-server-2005 recursion hierarchy common-table-expression

我有一个带有以下列的'Task'表(TaskOrder用于排序父级范围内的子级,而不是整个表):

TaskId
ParentTaskId
TaskName
TaskOrder

我有这个CTE查询返回所有行:

with tasks (TaskId, ParentTaskId, [Name]) as
(
    select parentTasks.TaskId,
           parentTasks.ParentTaskId,
           parentTasks.[Name]
    from   Task parentTasks
    where  ParentTaskId is null

    union all

    select childTasks.TaskId,
           childTasks.ParentTaskId,
           childTasks.[Name]
    from   Task childTasks
    join   tasks
    on     childTasks.ParentTaskId = tasks.TaskId
)

select * from tasks

此查询按预期返回按其级别排序的所有任务。如何更改它以将结果按照以下顺序排列?

- Task 1
-- Task 1 Subtask 1
-- Task 1 Subtask 2
- Task 2
- Task 3

感谢。

修改:答案应该使用无限数量的等级。

4 个答案:

答案 0 :(得分:3)

您可以这样做的一种方法是添加一个层次结构列,列中包含所有以前的ID:

with tasks (TaskId, ParentTaskId, [Name], TaskIdList) as
(
    select parentTasks.TaskId,
           parentTasks.ParentTaskId,
           parentTasks.[Name],
           parentTasks.TaskId
    from   Task parentTasks
    where  ParentTaskId is null

    union all

    select childTasks.TaskId,
           childTasks.ParentTaskId,
           childTasks.[Name],
           tasks.TaskIdList + '.' + childTasks.TaskId
    from   Task childTasks
    join   tasks
    on     childTasks.ParentTaskId = tasks.TaskId
)

select TaskId, ParentTaskId, [Name] from tasks
   order by TaskIdList

请注意,这假设TaskId是基于字符串的ID。如果没有,您应该在连接之前将其转换为varchar。

答案 1 :(得分:2)

使用Mark's method的变体解决了问题,但我没有在每个节点中保留节点路径,因此我可以更轻松地在树中移动它们。相反,我将我的'OrderBy'列从int更改为varchar(3)左边填充零,这样我就可以将它们连接成一个主'OrderBy'来返回所有行。

with tasks (TaskId, ParentTaskId, OrderBy, [Name], RowOrder) as
(
    select  parentTasks.TaskId,
            parentTasks.ParentTaskId,
            parentTasks.OrderBy,
            parentTasks.[Name],
            cast(parentTasks.OrderBy as varchar(30)) 'RowOrder'
    from    Task parentTasks
    where   ParentTaskId is null

    union all

    select  childTasks.TaskId,
            childTasks.ParentTaskId,
            childTasks.OrderBy,
            childTasks.[Name],
            cast(tasks.RowOrder + childTasks.OrderBy as varchar(30)) 'RowOrder'
    from    Task childTasks
    join    tasks
    on      childTasks.ParentTaskId = tasks.TaskId
)

select * from tasks order by RowOrder

返回:

TaskId  ParentTaskId  OrderBy  Name                              RowOrder
---------------------------------------------------------------------------
1       NULL          001      Task One                          001
15      1             001      Task One / Task One               001001
2       NULL          002      Task Two                          002
7       2             001      Task Two / Task One               002001
14      7             001      Task Two / Task One / Task One    002001001
8       2             002      Task Two / Task Two               002002
9       8             001      Task Two / Task Two / Task One    002002001
10      8             002      Task Two / Task Two / Task Two    002002002
11      8             003      Task Two / Task Two / Task Three  002002003
3       NULL          003      Task Three                        003
4       NULL          004      Task Four                         004
13      4             001      Task Four / Task One              004001
5       NULL          005      Task Five                         005
6       NULL          006      Task Six                          006    
17      NULL          007      Task Seven                        007
18      NULL          008      Task Eight                        008
19      NULL          009      Task Nine                         009
21      19            001      Task Nine / Task One              009001
20      NULL          010      Task Ten                          010

它不允许无限制的层次结构(每个父节点最多10个级别/最多1000个子节点 - 如果我在0处启动OrderBy)但足以满足我的需求。

答案 2 :(得分:1)

你不需要所有联盟的东西,我认为这应该有效:

select
 TaskId,
 ParentTaskId,
 [Name],
 COALESCE(ParentTaskId, TaskId) as groupField
from
 task
order by
 COALESCE(ParentTaskId, TaskId), ParentTaskId, TaskId

答案 3 :(得分:0)

由于你没有指定“ORDER BY”,你怎么期望它以任何特定的顺序返回它们(除了希望查询分析器能以某种预期的方式工作?)。

如果你想在ParentTaskId,TaskId顺序中使用它,那么在第一个UNION元素中选择TaskId作为ParentTaskId和NULL作为TaskId;然后

ORDER BY ParentTaskId,TaskId?