Domanda

Ho un database di "elenco attività" che utilizza il modello di elenco di adiacenza (vedi sotto) in modo che ogni "compito" possa avere attività secondarie illimitate. La tabella ha una colonna "TaskOrder", quindi tutto viene visualizzato nell'ordine corretto in una vista ad albero.

Esiste un'istruzione SQL (MS-SQL 2005) che selezionerà tutti i nodi figlio per un genitore specificato e aggiornerà la colonna TaskOder quando viene eliminato un fratello?

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

Qualche idea? Grazie.

È stato utile?

Soluzione

Un paio di modi diversi ... Dato che TaskOrder ha come ambito l'id padre, non è terribilmente difficile raccoglierlo. In SQL Server, metterei un trigger su delete che diminuisce tutti quelli "più alti" di quello che hai eliminato, chiudendo così il gap (segue lo pseudocodice):

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

Se non si desidera un trigger, è possibile acquisire parentID e TaskOrder prima in una query, eliminare la riga, quindi eseguire la stessa istruzione di aggiornamento ma con valori letterali anziché il trigger.

O se si desidera ridurre al minimo i round trip del server, è possibile spostare l'attività da eliminare fino in fondo, quindi spostare gli altri verso l'alto, quindi eliminare, ma sembra eccessivamente complicato.

Altri suggerimenti

Se stai utilizzando TaskOrder solo per l'ordinamento, sarebbe sicuramente più semplice lasciare semplicemente i buchi in TaskOrder, perché semplicemente l'eliminazione degli elementi non renderà l'ordinamento errato. Ma poi non sono sicuro delle esigenze della tua applicazione.

Non direttamente. Questo è un ordinamento topologico in cui stai "appendendo" i nodi figlio a un genitore. Se non vi è dipendenza all'interno dei figli, l'ordine con cui vengono eseguiti non ha importanza. Se i bambini devono essere eseguiti in un certo ordine, allora non hai abbastanza informazioni per dedurlo - dovrebbero avere livelli gerarchici aggiuntivi.

Supponendo che l'ordine dei bambini all'interno di un genitore sia irrilevante, un ordinamento topoligico ti procurerà ciò che desideri. Non lo otterrai in una singola query nella maggior parte dei dialetti SQL, ma dovrai scrivere uno sproc per farlo.

Se l'ordine dei figli all'interno del nodo è rilevante, è necessario mantenere l'ordine delle attività all'interno del genitore. Una query che utilizza ParentNodeID, TaskOrder e count (*) selezionerà i duplicati, ma a meno che il sistema non disponga di informazioni aggiuntive per ordinare le attività, sarà comunque necessario un intervento manuale per selezionare l'ordine corretto.

Per favore, aggiungi commenti se vuoi che chiarisca qualcosa.

Sembra un lavoro per ROW_Number.

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

Elimina attività 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;

Ovviamente, potresti eliminare l'eliminazione e lasciare il record in sospeso per scopi di report futuri.

CAVEAT: NON TESTATO !!!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top