5

ich eine ‚Aufgabe‘ Tabelle mit den folgenden Spalten habe (die Taskorder ist es, die Kinder im Rahmen der Mutter für die Bestellung, nicht die gesamte Tabelle):Reihenfolge Hierarchie aus rekursiven Abfrageergebnissen in SQL 2005

 
TaskId 
ParentTaskId 
TaskName 
TaskOrder 

ich habe diese CTE-Abfrage habe alle Zeilen zurückgeben:

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 

Diese Abfrage liefert alle von ihrem Niveau bestellt Aufgaben wie man erwarten würde. Wie kann ich es ändern, um die Ergebnisse in ihre hierarchische Reihenfolge wie folgt zu ordnen?

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

Danke.

Bearbeiten: Die Antwort sollte mit einer unbegrenzten Anzahl von Ebenen arbeiten.

+0

Experimentieren Sie nur mit CTEs, oder ist das einfacher als reines SQL? – dkretz

+0

Ja, experimentieren mit CTE, aber wenn es eine bessere Lösung mit geraden SQL gibt werde ich das verwenden .. – Nick

Antwort

2

Gelöst ist das Problem, eine Variation von Mark's method, aber ich bin nicht der Knoten Pfad in jedem Knoten beibehalten wird, so Ich kann sie leichter um den Baum bewegen. Statt dessen habe ich meine 'OrderBy'-Spalte von einem int nach varchar (3) mit Nullen aufgefüllt, so dass ich sie für alle zurückgegebenen Zeilen zu einem Master' OrderBy 'verketten kann.

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 

Das gibt:

 
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 

Es ist nicht für eine unbegrenzte Hierarchie erlaubt (max 10 Stufen/max 1000 Kinder pro Elternknoten - wenn ich die OrderBy bei 0 begonnen hatte), aber mehr als genug für meine Bedürfnisse.

3

Eine Möglichkeit, dies tun könnte, ist eine Hierarchiespalte hinzuzufügen, die alle vorherigen IDs in einer Liste hat:

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 

Beachten Sie, dass dies setzt voraus, dass TaskId ein String-basierten ID ist. Wenn nicht, sollten Sie es vor der Verkettung in einen Varchar umwandeln.

+0

Danke, hoffte, eine Lösung zu finden, die keine zusätzlichen Spalten benötigt; Das macht es etwas schwieriger zu warten, wenn untergeordnete Aufgaben zwischen Eltern verschoben werden. – Nick

0

Da Sie "ORDER BY" nicht angeben, wie erwarten Sie, dass es sie in einer bestimmten Reihenfolge zurückgibt (außer in der Hoffnung, dass der Abfrageanalysator in irgendeiner erwarteten Weise funktioniert?).

Wenn Sie es in ParentTaskId, TaskId Reihenfolge möchten, dann wählen Sie die TaskId als ParentTaskId und NULL als TaskId im ersten UNION-Element; dann

ORDER BY ParentTaskId, TaskId?

+0

Richtig, große Unterlassung! Ich habe auch eine 'Bestellung von' Spalte für die Bestellung der Kinder innerhalb der Eltern – Nick

1

Sie nicht alle diese Vereinigung Sachen brauchen, ich denke, das sollte funktionieren:

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

Fast, aber funktioniert nur für 2 Ebenen. Ich brauche mehr .. Danke – Nick