SQL重排层次结构中的节点

3
我有一个“任务列表”数据库,使用邻接列表模型(如下所示),因此每个“任务”可以有无限的子任务。该表具有“TaskOrder”列,因此所有内容都会按正确顺序呈现在树视图中。
是否有一种SQL语句(MS-SQL 2005)可以选择指定父节点的所有子节点,并在删除兄弟节点时更新TaskOder列?
任务表 ---------- 任务ID 父任务ID 任务顺序 任务名称 --等等--
有什么想法吗?谢谢。
5个回答

2
如果您只是使用TaskOrder进行排序,那么简单地将TaskOrder中的空位保留下来会更加简单,因为仅仅删除项目并不会使排序失效。但我不确定您的应用程序的需求。

1

有几种不同的方法...由于TaskOrder是由父ID范围限定的,因此收集它并不是非常困难。在SQL Server中,我会在删除时放置一个触发器,将所有比您删除的任务序号“高”的任务序号递减,从而关闭间隙(伪代码如下):

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

如果您不想使用触发器,可以先在查询中捕获parentID和TaskOrder,然后删除行,再执行相同的更新语句,但使用文字而不是触发器。
或者,如果您想最小化服务器往返次数,可以将要删除的任务移动到底部,然后将其他任务向上移动,然后进行删除,但这似乎过于复杂。

0

不是直接的。这是一个拓扑排序,您需要将子节点“挂”在父节点上。如果子节点之间没有依赖关系,则它们执行的顺序并不重要。如果子节点必须按特定顺序执行,则您没有足够的信息来推断这一点 - 它们必须具有额外的层次结构。

假设父节点内子节点的顺序无关紧要,则拓扑排序将为您提供所需的结果。在大多数SQL方言中,您无法将其转换为单个查询 - 您必须编写存储过程来执行此操作。

如果节点内子节点的顺序很重要,则需要在父节点内维护任务顺序。使用ParentNodeID、TaskOrder和count(*)的查询将选择重复项,但除非系统具有其他信息来排序任务,否则仍需要手动干预以选择正确的顺序。

如果您想让我澄清某些内容,请添加评论。


0

这看起来像是 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

0

删除任务 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;

当然,你可以删除它,只是为了将来的报告目的而让记录留在那里。

注意:未经测试!!!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接