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

发布于 2024-07-13 08:38:20 字数 797 浏览 10 评论 0原文

我有一个包含以下列的“任务”表(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

谢谢。

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

I've got a 'Task' table with the following columns (the TaskOrder is for ordering the children within the scope of the parent, not the entire table):

TaskId
ParentTaskId
TaskName
TaskOrder

I've got this CTE query to return all the rows:

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

This query returns all the tasks ordered by their level as you'd expect. How can I change it to order the results into their hierarchy order as below?

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

Thanks.

Edit: The answer should work with an unlimited numbr of levels.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

风流物 2024-07-20 08:38:20

执行此操作的一种方法是添加一个层次结构列,其中包含列表中的所有先前 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。

One way you could do this is to add a hierarchy column that has all previous IDs in a list:

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

Note that this assumes that TaskId is a string-based ID. If not, you should cast it to a varchar before concatenating it.

雅心素梦 2024-07-20 08:38:20

使用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  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),但足以满足我的需求。

Solved the problem using a variation of Mark's method, but I'm not retaining the node path in every node, so I can more easily move them around the tree. Instead I changed my 'OrderBy' column from an int to varchar(3) left-padded with zeros so I can concatenate them into a master 'OrderBy' for all the rows returned.

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

This returns:

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

It doesn't allow for an unlimited hierarchy (max 10 levels / max 1000 children per parent node - if I'd started the OrderBy at 0) but more than enough for my needs.

梅窗月明清似水 2024-07-20 08:38:20

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

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

You don't need all that union stuff, I think this should work:

select
 TaskId,
 ParentTaskId,
 [Name],
 COALESCE(ParentTaskId, TaskId) as groupField
from
 task
order by
 COALESCE(ParentTaskId, TaskId), ParentTaskId, TaskId
想你只要分分秒秒 2024-07-20 08:38:20

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

如果您希望按 ParentTaskId、TaskId 顺序排列,则在第一个 UNION 元素中选择 TaskId 作为 ParentTaskId,并选择 NULL 作为 TaskId; 那么

ORDER BY ParentTaskId, TaskId?

Since you don't specify "ORDER BY", how do you expect that it returns them in any particular order (other than hoping the query analyzer will work in some expected fashion?).

If you want it in ParentTaskId, TaskId order, then select the TaskId as ParentTaskId and NULL as TaskId in the first UNION element; then

ORDER BY ParentTaskId, TaskId?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文