Упорядочение иерархии на основе результатов рекурсивного запроса в SQL 2005
-
22-08-2019 - |
Вопрос
У меня есть таблица «Задача» со следующими столбцами (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
Спасибо.
Редактировать: Ответ должен работать с неограниченным количеством уровней.
Решение 2
Решил проблему, используя вариант метод Марка, но я не сохраняю путь узла в каждом узле, поэтому мне легче перемещать их по дереву.Вместо этого я изменил свой столбец 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), но для моих нужд более чем достаточно.
Другие советы
Один из способов сделать это — добавить столбец иерархии, в котором есть все предыдущие идентификаторы в списке:
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 перед объединением.
Вам не нужны все эти союзы, я думаю, это должно сработать:
select
TaskId,
ParentTaskId,
[Name],
COALESCE(ParentTaskId, TaskId) as groupField
from
task
order by
COALESCE(ParentTaskId, TaskId), ParentTaskId, TaskId
Поскольку вы не указываете «ORDER BY», как вы ожидаете, что он вернет их в каком-либо определенном порядке (кроме надежды, что анализатор запросов будет работать каким-то ожидаемым образом?).
Если вы хотите, чтобы это было в порядке ParentTaskId, TaskId, выберите TaskId в качестве ParentTaskId и NULL в качестве TaskId в первом элементе UNION;затем
ЗАКАЗАТЬ ПО ParentTaskId, TaskId?