SQL para nós reordenar em uma hierarquia
-
02-07-2019 - |
Pergunta
Eu tenho um banco de dados 'lista de tarefas' que utiliza o modelo de lista de adjacência (veja abaixo) para cada 'tarefa' pode ter sub-tarefas ilimitadas. A tabela tem coluna de um 'TaskOrder' assim tudo torna na ordem correta em uma árvore.
Existe uma instrução SQL (MS-SQL 2005) que irá selecionar todos os nós filho para um pai especificado e atualizar a coluna TaskOder quando um irmão é excluído?
Task Table ---------- TaskId ParentTaskId TaskOrder TaskName --etc--
Todas as idéias? Obrigado.
Solução
Os pares de maneiras diferentes ... Desde o TaskOrder tem como escopo por id pai, não é terrivelmente difícil reunir-lo. No SQL Server, eu ia colocar um gatilho de exclusão que diminui todos os 'maior' do que o que você excluído, assim fechando a lacuna (pseudocódigo segue):
CREATE TRIGGER ON yourtable FOR DELETE
AS
UPDATE Task
SET TaskOrder = TaskOrder - 1
WHERE ParentTaskId = deleted.ParentTaskId
AND TaskOrder > deleted.TaskOrder
Se você não quer um gatilho, você pode capturar a parentID e TaskOrder em uma consulta primeiro, excluir a linha, em seguida, executar essa mesma instrução de atualização, mas com literais em vez do gatilho.
Ou se você quiser minimizar servidor round-trips, você pode mover a tarefa para-ser-eliminado todo o caminho até o fundo, em seguida, passar os outros para cima, em seguida, fazer a exclusão, mas que parece excessivamente complicado.
Outras dicas
Se você estiver usando apenas TaskOrder para a classificação, certamente seria mais simples simplesmente deixar os buracos em TaskOrder, porque os itens simplesmente apagar não vai fazer a incorreta classificação. Mas então eu não tenho certeza sobre as necessidades do seu aplicativo.
Não diretamente. Esta é uma topológica Ordenar onde você está 'pendurado' os nós filhos fora de um pai. Se não há nenhuma dependência nas crianças a fim de que eles são executados não importa. Se as crianças devem ser executadas em uma determinada ordem, então você não tem informação suficiente para inferir isso -. Eles teriam que ter níveis adicionais de hierarquia
Assumindo que o fim das crianças dentro de um pai é irrelevante, em seguida, uma espécie topoligical vai ter o que você quer. Você não vai conseguir isso em uma única consulta, na maioria dos dialetos SQL -. Você terá que escrever um sproc para fazê-lo
Se a ordem das crianças dentro do nó é relevante, então você precisa para manter a ordem tarefa dentro do pai. A consulta usando ParentNodeID, TaskOrder e count (*) irá escolher duplicatas mas a menos que o sistema tem informações adicionais para ordenar as tarefas que você ainda vai precisar de intervenção manual para seleccionar a ordem correta.
Por favor adicionar comentários se você quiser me esclarecer uma coisa.
Isto parece um trabalho para 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
tarefa Excluir 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;
Claro, você poderia eliminar a exclusão, e apenas deixar o registro em torno de mentir para relatar futuros propósitos.
ressalva: NÃO TESTADO !!!