5

我有一个“任务”表具有以下的列(在TaskOrder是父,而不是整个表的范围内订购儿童):订购层次2005

 
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 

谢谢。

编辑:答案应该可以使用无限数量的关卡。你可以这样做

+0

你只是试验CTE,还是比直接SQL更简单? – dkretz 2009-02-11 22:53:38

+0

是的,试验CTE,但如果有更好的解决方案,直接使用SQL我会使用.. – Nick 2009-02-11 23:04:31

回答

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开始排序依据),但更多的对我的需求来说足够了。

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。

+0

谢谢,希望找到一个解决方案,不需要额外的列;这使得当孩子的任务在父母之间移动时难以维持。 – Nick 2009-02-12 18:23:55

0

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

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

ORDER BY ParentTaskId,TaskId?

+0

正确,重大遗漏!我还订购了一个'order by'列,用于订购家长中的子女 – Nick 2009-02-12 18:26:19

1

你并不需要所有的工会的东西,我觉得这应该工作:

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