我有一个使用邻接列表模型(见下文)的“任务列表”数据库,因此每个“任务”可以有无限的子任务。该表有一个“TaskOrder”列,因此所有内容都以正确的顺序呈现在树视图上。

是否有一个 SQL 语句(MS-SQL 2005)将选择指定父节点的所有子节点,并在删除同级节点时更新 TaskOder 列?

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

有任何想法吗?谢谢。

有帮助吗?

解决方案

几种不同的方式...由于 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,删除该行,然后执行相同的更新语句,但使用文字而不是触发器。

或者,如果您想最大程度地减少服务器往返次数,您可以将要删除的任务一直移动到底部,然后将其他任务向上移动,然后进行删除,但这似乎过于复杂。

其他提示

如果您仅使用 TaskOrder 进行排序,那么直接在 TaskOrder 中保留漏洞肯定会更简单,因为仅删除项目不会导致排序不正确。但我不确定您的应用程序的需求。

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

假设父级中子级的顺序无关,那么拓扑排序将得到您想要的结果。在大多数 SQL 方言中,您不会将其放入单个查询中 - 您必须编写一个存储过程来完成它。

如果节点内子节点的顺序相关,那么您需要维护父节点内的任务顺序。使用 ParentNodeID、TaskOrder 和计数 (*) 的查询将挑选出重复项,但除非系统有其他信息来对任务进行排序,否则您仍然需要手动干预来选择正确的顺序。

如果您想让我澄清一些事情,请添加评论。

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

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

当然,您可以消除删除,并将记录保留下来以供将来报告之用。

警告:未测试!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top