Порядок иерархии из результатов рекурсивных запросов в SQL 2005 - PullRequest
5 голосов
/ 12 февраля 2009

У меня есть таблица '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 ]

3 голосов
/ 12 февраля 2009

Один из способов сделать это - добавить столбец иерархии со всеми предыдущими идентификаторами в списке:

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 является строковым идентификатором. Если нет, вы должны привести его к varchar, прежде чем объединять его.

2 голосов
/ 13 февраля 2009

Решил проблему, используя вариант Метод Марка , но я не сохраняю путь к узлу в каждом узле, поэтому мне легче перемещать их по дереву. Вместо этого я изменил свой столбец «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 дочерних элементов на родительский узел - если бы я начал OrderBy с 0), но более чем достаточно для моих нужд.

1 голос
/ 12 февраля 2009

Вам не нужны все эти профсоюзные штуки, я думаю, что это должно сработать:

select
 TaskId,
 ParentTaskId,
 [Name],
 COALESCE(ParentTaskId, TaskId) as groupField
from
 task
order by
 COALESCE(ParentTaskId, TaskId), ParentTaskId, TaskId
0 голосов
/ 12 февраля 2009

Поскольку вы не указываете "ORDER BY", как вы ожидаете, что он возвращает их в каком-то конкретном порядке (кроме надежды, что анализатор запросов будет работать каким-то ожидаемым образом?).

Если вы хотите использовать его в порядке ParentTaskId, TaskId, выберите TaskId в качестве ParentTaskId и NULL в качестве TaskId в первом элементе UNION; то

ORDER BY ParentTaskId, TaskId?

...