【问题标题】:SQL Stored Procedure: Reordering rows after deleteSQL 存储过程:删除后重新排序行
【发布时间】:2012-07-16 23:51:48
【问题描述】:

在我的数据库中,我有如下三个表:

  • Tasks (TaskID, TaskName, TaskDescription)
  • TaskDetails (TaskID, subTaskPosition, SubTaskID)
  • Subtasks (SubTaskID, Description)

我正在尝试编写一个Stored Procedure 来完全删除一个SubTask,然后将另一个SubTasks 重新排序为一个Task

注意事项:

  • TaskDetails 链接 Tasks 到成员 SubTasks
  • SubTask 可能在许多不同的任务中被引用。
  • Task 应由 SubTasks 的有序列表组成...即 1,2,3,4 而不是 1,3,4,5。

删除SubTask 及其与Task 的链接相当容易,如下所示:

  • DELETE FROM TaskDetails WHERE SubTaskID = @subTaskID
  • DELETE FROM SubTasks WHERE SubTaskID = @subTaskID

但是,一旦最初的 SubTask 被删除,我无法理解如何重新排序 TaskDetails 表中的另一个 SubTasks。在英语中,我需要执行以下操作 - “对于刚刚从中删除 SubTask 的所有任务,从删除行所在位置之后出现的所有 subTaskPosition 字段中减去 1”。

任何帮助或指针表示赞赏...

戈登

【问题讨论】:

  • 这是什么 SQL 类型?甲骨文、微软 SQL 服务器? DB2? MySql?
  • 对不起,我应该说 - MS SQL Server (2012) - 虽然它也需要在 Azure SQL 上运行!感谢您在下面的回复 - 我稍后会尝试并让您知道我的进展情况。非常感谢!

标签: sql sql-server stored-procedures azure-sql-database sql-server-2012


【解决方案1】:

我认为您必须为每项任务进行更新。这样就可以解决问题(语法适用于 SQL Server):

DECLARE @TaskID int
DECLARE @SubTaskPosition int

DECLARE curSubTaskPositionUpdate cursor fast_forward
FOR 
    SELECT TaskID, SubTaskPosition
    FROM TaskDetails 
    WHERE SubTaskID = @SubTaskID
OPEN curSubTaskPositionUpdate
FETCH NEXT FROM curSubTaskPositionUpdate INTO @TaskID, @SubTaskPosition
WHILE @@FETCH_STATUS = 0
    BEGIN   
        UPDATE TaskDetails
        SET SubTaskPosition = SubTaskPosition - 1
        WHERE TaskID = @TaskID
        AND SubTaskPosition > @SubTaskPosition

        FETCH NEXT FROM curSubTaskPositionUpdate INTO @TaskID, @SubTaskPosition
    END
CLOSE curSubTaskPositionUpdate
DEALLOCATE curSubTaskPositionUpdate

请注意,您在从 TaskDetails 中删除之前执行此操作...并且您可能希望将所有内容包装在事务中。

Gordon Edit - 我必须在更新代码中包含我的删除代码才能使其正常工作,否则(a)首先发生删除并且“其中 subtaskID = @subtaskID”没有返回任何内容,或者(b)我在之后进行了删除重新排序和重新排序(正确!)没有效果。

DECLARE @TaskID uniqueidentifier
DECLARE @SubTaskPosition int 

DECLARE curSubTaskPositionUpdate cursor fast_forward 
FOR  
    SELECT TaskID, SubTaskPosition 
    FROM TaskDetails  
    WHERE SubTaskID = @subTaskID 
OPEN curSubTaskPositionUpdate 
FETCH NEXT FROM curSubTaskPositionUpdate INTO @TaskID, @SubTaskPosition 
WHILE @@FETCH_STATUS = 0 
   BEGIN    
-- Delete the subTask
DELETE FROM TaskDetails
WHERE TaskID = @TaskID
AND SubTaskPosition = @SubTaskPosition 

-- Update the other subTasks
        UPDATE TaskDetails
        SET SubTaskPosition = SubTaskPosition - 1
        WHERE TaskID = @TaskID
        AND SubTaskPosition > @SubTaskPosition

        FETCH NEXT FROM curSubTaskPositionUpdate INTO @TaskID, @SubTaskPosition
    END
CLOSE curSubTaskPositionUpdate
DEALLOCATE curSubTaskPositionUpdate

【讨论】:

  • 感谢 James,通过一些小的调整,我设法让它工作了 - 尽管如果我可以调整 Barry 的代码可能会更有效率!
【解决方案2】:

应该这样做:

UPDATE  TaskDetails
SET     subTaskPosition = ROW_NUMBER() OVER(PARTITION BY TaskID  ORDER BY subTaskPosition) 
WHERE   TaskID IN(  SELECT  s.TaskID 
                    FROM    TaskDetails s 
                    WHERE   SubTaskID = @subTaskID)

不需要循环...请注意,这也适用于缺少多个子任务或已为同一任务删除的情况。


好的,这是 SQL Server 的更正版本:

;WITH
  cteRows As
(
    SELECT  *,
    ROW_NUMBER() OVER(PARTITION BY TaskID  ORDER BY subTaskPosition) As NewPosition
    FROM    TaskDetails
)
UPDATE  cteRows
SET     subTaskPosition = NewPosition
WHERE   TaskID IN(  SELECT  s.TaskID 
                    FROM    TaskDetails s 
                    WHERE   SubTaskID = @subTaskID)

抱歉耽搁了……

【讨论】:

  • 我喜欢!需要注意的是,它可能会更新不需要更新的行。我也认为它应该是“WHERE TaskID IN(”。
  • 这是一个值子查询,它与 IN 或 EXISTS 子查询同样有效(它们通常(但不总是)可互换)
  • 嗨,巴里,非常感谢您在这方面的帮助。这可能是因为我没有指定我使用的是 SQL Server,但我收到错误消息“窗口函数只能出现在 SELECT 或 ORDER BY 子句中。”。有什么想法吗?
  • 非常感谢 Barry - 这个看似简单的工作其实很费力。不幸的是,您的代码在我的应用程序中不起作用。我 认为 的原因是因为我必须在重新订购代码之前从 TaskDetails 表中删除 subTask,所以您的“WHERE SubTaskID = @subTaskID”找不到任何东西。如果您想看一下,我已经设法让 James 的代码在下面工作了 - 尽管我相信您几乎有一个更优雅的解决方案。再次感谢。
【解决方案3】:

先获取子rask的位置,删除,更新记录:

declare @pos int
select @pos = subTaskPosition from TaskDetails where SubTaskID = @subTaskID
delete ...
delete ...
update TaskDetails set subTaskPosition = subTaskPosition + 1 where SubTaskID = @subTaskID and subTaskPosition > @pos

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-02
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多