5

Tengo mesa de una 'misión' con las siguientes columnas (la TaskOrder es para pedir a los niños en el ámbito de los padres, no toda la tabla):Orden de los resultados de consultas recursivas en SQL 2005

 
TaskId 
ParentTaskId 
TaskName 
TaskOrder 

Tengo esta consulta CTE para devolver todas las filas:

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 

esta consulta devuelve todas las tareas ordenadas por su nivel como era de esperar. ¿Cómo puedo cambiarlo para ordenar los resultados en el orden jerárquico que se muestra a continuación?

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

Thanks.

Editar: La respuesta debería funcionar con un número ilimitado de niveles.

+0

¿Estás experimentando con CTE, o es más simple para ti que SQL directo? – dkretz

+0

Sí, experimentando con CTE, pero si hay una mejor solución con SQL directo lo usaré ... – Nick

Respuesta

2

resuelto el problema usando una variación de Mark's method, pero no estoy reteniendo el camino nodo en cada nodo, por lo Puedo moverlos más fácilmente alrededor del árbol. En su lugar, cambié mi columna 'OrderBy' de un int a varchar (3) a la izquierda con ceros para que pueda concatenarlos en un master 'OrderBy' para todas las filas devueltas.

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 

Esto devuelve:

 
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 

No permite por una jerarquía ilimitada (máximo 10 niveles/max 1000 niños por nodo padre - si es que había empezado el OrdenarPor a 0), pero más más que suficiente para mis necesidades

3

Una forma de poder hacer esto es añadir una columna de jerarquía que tiene todos los ID anteriores en una lista:

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 

Tenga en cuenta que esto supone que TaskId es un identificador basado en cadena. De lo contrario, debe convertirlo en varchar antes de concatenarlo.

+0

Gracias, esperaba encontrar una solución que no requiriera columnas adicionales; esto hace que sea un poco más difícil de mantener cuando las tareas del niño se mueven entre los padres. – Nick

0

Dado que no especifica "ORDER BY", ¿cómo espera que los devuelva en un orden en particular (que no sea esperar que el analizador de consultas funcione de la manera esperada?).

Si lo desea en ParentTaskId, orden de TaskId, seleccione TaskId como ParentTaskId y NULL como TaskId en el primer elemento de UNION; luego

¿PEDIDO por ParentTaskId, TaskId?

+0

¡Correcta, gran omisión! También tengo una columna 'ordenar por' para ordenar los niños dentro del padre – Nick

1

Usted no necesita todas esas cosas unión, creo que esto debería funcionar:

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

Casi, pero solo funciona para 2 niveles. Necesito más ... Gracias – Nick

Cuestiones relacionadas