2008-09-29 9 views
3

Ich habe eine 'Aufgabenliste' Datenbank, die das Adjazenzlistenmodell verwendet (siehe unten), so dass jede 'Task' unbegrenzte Teilaufgaben haben kann. Die Tabelle hat eine 'TaskOrder' Spalte, so dass alles in der richtigen Reihenfolge in einer Baumansicht dargestellt wird.SQL zum Neuordnen von Knoten in einer Hierarchie

Gibt es eine SQL-Anweisung (MS-SQL 2005), die alle untergeordneten Knoten für ein bestimmtes übergeordnetes Element auswählt und die Spalte TaskOder aktualisiert, wenn ein untergeordnetes Element gelöscht wird?

 
Task Table 
---------- 
TaskId 
ParentTaskId 
TaskOrder 
TaskName 
--etc-- 

Irgendwelche Ideen? Vielen Dank.

Antwort

1

Ein paar verschiedene Wege ... Da der TaskOrder von der Eltern-ID bestimmt wird, ist es nicht besonders schwierig, ihn zu erfassen. In SQL Server, würde ich einen Trigger auf löschen setzen, dass alle ‚höheren‘ diejenigen dekrementiert als die, die Sie dadurch gelöscht, Schließen der Lücke (Pseudo-Code folgt):

CREATE TRIGGER ON yourtable FOR DELETE 
AS 
    UPDATE Task 
    SET TaskOrder = TaskOrder - 1 
    WHERE ParentTaskId = deleted.ParentTaskId 
    AND TaskOrder > deleted.TaskOrder 

Wenn Sie keinen Trigger wollen Sie können zuerst die ParentID und den TaskOrder in einer Abfrage erfassen, dann die Zeile löschen und dann dieselbe Update-Anweisung ausführen, jedoch mit Literalen anstelle des Triggers.

Oder wenn Sie Server-Round-Trips minimieren möchten, können Sie die zu löschende Aufgabe ganz nach unten verschieben, dann die anderen verschieben und dann löschen, aber das scheint übermäßig kompliziert.

2

Wenn Sie TaskOrder nur zum Sortieren verwenden, wäre es sicherlich einfacher, die Löcher in TaskOrder zu belassen, da das Löschen von Elementen die Sortierung nicht inkorrekt macht. Aber ich bin mir nicht sicher über die Anforderungen Ihrer Anwendung.

0

Nicht direkt. Dies ist ein Topological Sort, in dem Sie die untergeordneten Knoten eines übergeordneten Elements "hängen". Wenn innerhalb der Kinder keine Abhängigkeit besteht, spielt die Reihenfolge, in der sie ausgeführt werden, keine Rolle. Wenn die Kinder in einer bestimmten Reihenfolge ausgeführt werden müssen, haben Sie nicht genug Informationen, um daraus zu schließen - sie müssten zusätzliche Hierarchieebenen haben.

Unter der Annahme, dass die Reihenfolge der Kinder in einem Elternteil irrelevant ist, bekommt eine topoligische Sortierung, was Sie wollen. Sie werden dies in den meisten SQL-Dialekten nicht in eine einzige Abfrage bringen - Sie müssen dafür einen Sproc schreiben.

Wenn die Reihenfolge der untergeordneten Elemente innerhalb des Knotens relevant ist, müssen Sie die Reihenfolge der Aufgaben innerhalb des übergeordneten Elements beibehalten. Eine Abfrage mit ParentNodeID, TaskOrder und count (*) wählt Duplikate aus. Wenn dem System jedoch keine zusätzlichen Informationen zur Verfügung stehen, um die Aufgaben zu ordnen, müssen Sie noch manuell eingreifen, um die richtige Reihenfolge auszuwählen.

Bitte fügen Sie Kommentare hinzu, wenn Sie möchten, dass ich etwas klarstelle.

0

Das sieht wie ein Job für ROW_Number aus.

DECLARE @Tasks TABLE 
(
    TaskId int PRIMARY KEY, 
    ParentTaskId int, 
    TaskOrder int, 
    TaskName varchar(30) 
) 

INSERT INTO @Tasks(TaskId, ParentTaskId, TaskOrder, TaskName) 
SELECT 1, null, 1, 'ParentTask' 

INSERT INTO @Tasks(TaskId, ParentTaskId, TaskOrder, TaskName) 
SELECT 2, 1, 2, 'B' 

INSERT INTO @Tasks(TaskId, ParentTaskId, TaskOrder, TaskName) 
SELECT 3, 1, 1, 'A' 

INSERT INTO @Tasks(TaskId, ParentTaskId, TaskOrder, TaskName) 
SELECT 4, 1, 3, 'C' 
--Initial 
SELECT * FROM @Tasks WHERE ParentTaskId = 1 ORDER BY TaskOrder 

DELETE FROM @Tasks WHERE TaskId = 2 
--After Delete 
SELECT * FROM @Tasks WHERE ParentTaskId = 1 ORDER BY TaskOrder 


UPDATE t 
SET TaskOrder = NewTaskOrder 
FROM @Tasks t 
    JOIN 
(
SELECT TaskId, ROW_Number() OVER(ORDER BY TaskOrder) as NewTaskOrder 
FROM @Tasks 
WHERE ParentTaskId = 1 
) sub ON t.TaskId = sub.TaskId 

--After Update 
SELECT * FROM @Tasks WHERE ParentTaskId = 1 ORDER BY TaskOrder 
0

löschen Aufgabe 88:

UPDATE TaskTable 
SET ParentTaskID = (SELECT ParentTaskID AS temp FROM Task_Table t1 WHERE TaskID = 88) 
WHERE 
TaskID IN (SELECT TaskID task2 FROM TaskTable t2 WHERE ParentTaskID = 88); 
Delete FROM TaskTable WHERE TaskID = 88; 

Natürlich könnten Sie den Lösch beseitigen, und lassen Sie nur den Rekord um für zukünftige Berichterstattung liegen.

HÖHLE: NICHT GETESTET !!!