5

J'ai une table « tâche » avec les colonnes suivantes (le TaskOrder est pour commander les enfants dans le cadre de la société mère, pas la table entière):Commande hiérarchie des résultats de requête récursive dans SQL 2005

 
TaskId 
ParentTaskId 
TaskName 
TaskOrder 

J'ai cette requête CTE pour retourner toutes les lignes:

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 

cette requête renvoie toutes les tâches ordonnées par leur niveau que vous attendez. Comment puis-je le modifier pour ordonner les résultats dans leur ordre hiérarchique comme ci-dessous?

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

Merci.

Modifier: La réponse devrait fonctionner avec un nombre illimité de niveaux.

+0

Expérimentez-vous simplement avec des CTE, ou est-ce plus simple pour vous que le SQL? – dkretz

+0

Oui, j'expérimente avec CTE, mais s'il y a une meilleure solution avec SQL direct, je vais l'utiliser .. – Nick

Répondre

2

a résolu le problème en utilisant une variante de Mark's method, mais je ne suis pas en conservant le chemin de nœud dans chaque nœud, donc Je peux plus facilement les déplacer autour de l'arbre. Au lieu de cela j'ai changé ma colonne 'OrderBy' d'un int à varchar (3) avec des zéros à gauche afin que je puisse les concaténer en un maître 'OrderBy' pour toutes les lignes retournées.

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 

Ce retour:

 
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 

Il ne permet pas une hiérarchie illimitée (niveaux maximum 10/max 1000 enfants par nœud parent - si j'avais commencé le OrderBy à 0), mais plus que suffisant pour mes besoins.

3

Une façon que vous pourriez faire est d'ajouter une colonne hiérarchie qui a tous les ID précédents dans une liste:

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 

Notez que cela suppose que TaskId est une pièce d'identité basée sur la chaîne. Sinon, vous devriez le convertir en un varchar avant de le concaténer.

+0

Merci, espérait trouver une solution qui ne nécessite pas de colonnes supplémentaires; cela rend le maintien un peu plus difficile lorsque les tâches enfants sont déplacées entre les parents. – Nick

0

Puisque vous ne spécifiez pas "ORDER BY", comment voulez-vous qu'il les renvoie dans un ordre particulier (autre que d'espérer que l'analyseur de requête fonctionnera d'une manière attendue?).

Si vous le souhaitez dans ParentTaskId, TaskId order, sélectionnez alors TaskId comme ParentTaskId et NULL comme TaskId dans le premier élément UNION; puis

ORDER BY ParentTaskId, TaskId?

+0

Correct, grosse omission! J'ai aussi une colonne "commander par" pour commander les enfants dans le parent – Nick

1

Vous n'avez pas besoin de tout ce genre de choses de l'union, je pense que cela devrait fonctionner:

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

Presque, mais ne fonctionne que pour 2 niveaux. J'ai besoin de plus .. Merci – Nick