5

我有一个包含以下列的“任务”表(TaskOrder 用于在父级范围内对子级进行排序,而不是整个表):

任务 ID
父任务 ID
任务名称
任务顺序

我有这个 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

此查询返回您所期望的按级别排序的所有任务。如何更改它以将结果排序为如下的层次顺序?

- 任务1
-- 任务 1 子任务 1
-- 任务 1 子任务 2
- 任务 2
- 任务 3

谢谢。

编辑:答案应该适用于无限数量的级别。

4

4 回答 4

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。

于 2009-02-11T22:44:55.743 回答
2

使用Mark 方法的变体解决了这个问题,但我没有在每个节点中保留节点路径,因此我可以更轻松地在树周围移动它们。相反,我将我的 '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 名称 RowOrder
-------------------------------------------------- -------------------------
1 NULL 001 任务一 001
15 1 001 任务一/任务一 001001
2 NULL 002 任务二 002
7 2 001 任务二/任务一 002001
14 7 001 任务二/任务一/任务一 002001001
8 2 002 任务二 / 任务二 002002
9 8 001 任务二 / 任务二 / 任务一 002002001
10 8 002 任务二 / 任务二 / 任务二 002002002
11 8 003 任务二 / 任务二 / 任务三 002002003
3 NULL 003 任务三 003
4 NULL 004 任务四 004
13 4 001 任务四/任务一 004001
5 NULL 005 任务五 005
6 NULL 006 任务六 006    
17 NULL 007 任务七 007
18 NULL 008 任务八 008
19 NULL 009 任务九 009
21 19 001 任务九 / 任务一 009001
20 NULL 010 任务十 010

它不允许无限的层次结构(每个父节点最多 10 个级别/最多 1000 个子节点 - 如果我从 0 开始 OrderBy),但足以满足我的需要。

于 2009-02-12T21:42:27.257 回答
1

您不需要所有工会的东西,我认为这应该可行:

select
 TaskId,
 ParentTaskId,
 [Name],
 COALESCE(ParentTaskId, TaskId) as groupField
from
 task
order by
 COALESCE(ParentTaskId, TaskId), ParentTaskId, TaskId
于 2009-02-11T22:50:55.820 回答
0

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

如果您希望它按 ParentTaskId,TaskId 顺序,则在第一个 UNION 元素中选择 TaskId 作为 ParentTaskId 和 NULL 作为 TaskId;然后

按 ParentTaskId、TaskId 排序?

于 2009-02-11T22:45:47.707 回答