【问题标题】:Ordering hierarchy from recursive query results in SQL 2005SQL 2005 中递归查询结果的排序层次结构
【发布时间】:2009-02-11 22:31:12
【问题描述】:

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

谢谢。

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

【问题讨论】:

  • 您只是在试验 CTE,还是比直接 SQL 更简单?
  • 是的,正在尝试 CTE,但如果有更好的直接 SQL 解决方案,我会使用它..

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


【解决方案1】:

您可以这样做的一种方法是添加一个层次结构列,该列在列表中包含所有以前的 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。

【讨论】:

  • 谢谢,希望找到不需要额外列的解决方案;这使得在父母之间移动子任务时维护起来有点困难。
【解决方案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 名称 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)但足以满足我的需要。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

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

      按 ParentTaskId、TaskId 排序?

      【讨论】:

      • 正确,大遗漏!我也有一个“排序依据”列,用于对父级中的子级进行排序
      猜你喜欢
      • 2015-11-23
      • 2017-02-04
      • 1970-01-01
      • 2014-01-25
      • 1970-01-01
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      • 2013-02-09
      相关资源
      最近更新 更多