Sql 对表中的行重新排序的存储过程

Sql 对表中的行重新排序的存储过程,sql,sql-server,stored-procedures,Sql,Sql Server,Stored Procedures,我的任务是创建自定义存储过程: exec UPDATE_PROJECT_ORDER @PROJECTID=12, @UPDATEMODE=0 将在更新表中的行后执行 不幸的是,这让我真的很困惑(我甚至不确定这是否可能),我一直在尝试简化我正在做的事情,并想知道我是否可以就代码本身向董事会寻求帮助 因此,存储过程/代码的目的是按照顺序对项目列表进行重新排序,重新排序基于传入的参数进行更改,该参数将保留用户在表中设置的值,并对列表的其余部分进行排序,或将其重新编号为序列中的下一个数字。我想我们可以

我的任务是创建自定义存储过程:

exec UPDATE_PROJECT_ORDER @PROJECTID=12, @UPDATEMODE=0
将在更新表中的行后执行

不幸的是,这让我真的很困惑(我甚至不确定这是否可能),我一直在尝试简化我正在做的事情,并想知道我是否可以就代码本身向董事会寻求帮助

因此,存储过程/代码的目的是按照顺序对项目列表进行重新排序,重新排序基于传入的参数进行更改,该参数将保留用户在表中设置的值,并对列表的其余部分进行排序,或将其重新编号为序列中的下一个数字。我想我们可以假设UPDATEMODE=0在大多数情况下都是默认值

我有一张这样的桌子:

---------------------------------------
|   ID   |   POSITION   |   OLD_POS   |
---------------------------------------
|   10   |     1        |             |
|   11   |     2        |             |
|   12   |     3        |             |
|   13   |     4        |             |
---------------------------------------
如果用户决定给ID为12的记录(ID正在与存储过程一起传递)一个更高的优先级,例如1,那么应该发生的是其他记录(10/11/13)应该按顺序在其周围重新排序(2/3/4),这将影响它们在前端的显示方式,例如

---------------------------------------
|   ID   |   POSITION   |   OLD_POS   |
---------------------------------------
|   10   |     2        |      1      |
|   11   |     3        |      2      |
|   12   |     1        |      3      |
|   13   |     4        |      4      |
---------------------------------------
另一个例子是记录ID 12的位置从1更改为7,因此此数据集:

---------------------------------------
|   ID   |   POSITION   |   OLD_POS   |
---------------------------------------
|   10   |     2        |      1      |
|   11   |     3        |      2      |
|   12   |     1/7      |      3      |
|   13   |     4        |      4      |
---------------------------------------
位置数据被重新排序为:

---------------------------------------
|   ID   |   POSITION   |   OLD_POS   |
---------------------------------------
|   10   |     1        |      2      |
|   11   |     2        |      3      |
|   12   |     7        |      1      |
|   13   |     3        |      4      |
---------------------------------------
如上所述-在存储过程中,需要传入另一个参数(@UPDATEMODE,可以是0或1),该参数更改函数的行为,允许用户指定所需的位置,并对列表进行重新排序,而不是将其作为序列中的下一个数字,例如,它们将第3行中的优先级从值1更新为值7

此数据集第12行位置值=1,但更改为7,UPDATEMODE指定为1:

---------------------------------------
|   ID   |   POSITION   |   OLD_POS   |
---------------------------------------
|   10   |     2        |      1      |
|   11   |     3        |      2      |
|   12   |     1/7      |      3      |
|   13   |     4        |      4      |
---------------------------------------
将对列表重新排序如下:

---------------------------------------
|   ID   |   POSITION   |   OLD_POS   |
---------------------------------------
|   10   |     1        |      2      |
|   11   |     2        |      3      |
|   12   |     4        |      1      |
|   13   |     3        |      4      |
---------------------------------------
在此示例中,存储过程将被称为:

exec UPDATE_PROJECT_ORDER @PROJECTID=12, @UPDATEMODE=1
这是我一直在使用的SQL代码:

-- Declare variables
DECLARE @PROJECTID INTEGER
DECLARE @CURRENTPOSITION INTEGER
DECLARE @ROLLBACKPOSITION INTEGER
DECLARE @STARTPOSITION INTEGER
DECLARE @ENDPOSITION INTEGER

-- For testing hardcode a REQUEST ID
SET @PROJECTID = 12

-- Start Position value
SET @STARTPOSITION = 1

-- End Position value
SELECT @ENDPOSITION = COUNT(ID) FROM PROJECT WHERE PROJECT_ORDER IS NOT NULL

-- Update Rollback column with current value    
UPDATE PROJECT SET OLD_POS = POSITION WHERE POSITION IS NOT NULL

DECLARE cursorProjectPositionUpdate CURSOR fast_forward
FOR 
    SELECT ID, POSITION, OLD_POS
    FROM PROJECT 
    WHERE ID = @PROJECTID
    AND POSITION IS NOT NULL
OPEN cursorProjectPositionUpdate
FETCH NEXT FROM cursorProjectPositionUpdate INTO @PROJECTID, @CURRENTPOSITION, @ROLLBACKPOSITION

WHILE @@FETCH_STATUS = 0
    BEGIN   
        WHILE (@STARTPOSITION <= @ENDPOSITION)
            IF @STARTPOSITION = 1
                UPDATE PROJECT
                SET POSITION = @STARTPOSITION
                WHERE ID = @PROJECTID
                    AND OLD_POSITION = @ROLLBACKPOSITION

            ELSE
                UPDATE PROJECT
                SET POSITION = @STARTPOSITION
                WHERE OLD_POS = @ROLLBACKPOSITION
                    AND ID <> @PROJECTID
        SET @STARTPOSITION = @STARTPOSITION + 1
        FETCH NEXT FROM cursorProjectPositionUpdate INTO @PROJECTID, @CURRENTPOSITION, @ROLLBACKPOSITION
    END
CLOSE cursorProjectPositionUpdate
DEALLOCATE cursorProjectPositionUpdate
——声明变量
声明@projectd整数
声明@CURRENTPOSITION整数
声明@ROLLBACKPOSITION整数
声明@STARTPOSITION整数
声明@ENDPOSITION整数
--用于测试请求ID的硬代码
设置@PROJECTID=12
--起始位置值
设置@STARTPOSITION=1
--末端位置值
从项目订单不为空的项目中选择@ENDPOSITION=COUNT(ID)
--使用当前值更新回滚列
更新项目集旧位置=位置不为空的位置
声明游标ProjectPositionUpdate游标快进
对于
选择ID、位置、旧位置
从项目
其中ID=@PROJECTID
并且位置不为空
打开游标项目位置更新
从cursorProjectPositionUpdate获取下一个到@PROJECTID、@CURRENTPOSITION、@ROLLBACKPOSITION
而@@FETCH\u STATUS=0
开始

而(@STARTPOSITION您似乎可以通过两步流程来实现这一点:

  • 增加位置等于或大于目标位置且小于旧位置的所有项目的位置值
  • 更新应移动到目标位置的项目

  • 您可以使用两个update语句来实现这一点,甚至可以使用一个update语句,如果您在其中填充了一点
    CASE
    逻辑的话。

    看起来您可以通过两个步骤来实现这一点:

  • 增加位置等于或大于目标位置且小于旧位置的所有项目的位置值
  • 更新应移动到目标位置的项目

  • 你可以用两个update语句来实现这一点,或者甚至一个update语句,如果你在其中塞进一点
    CASE
    逻辑的话。

    我认为这是两种不同的可能性,要么在列表中上移,要么在列表中下移。剩下的只是位置上的算术运算,可以在一个update语句中完成

    create procedure update_project_order (@ProjectId int, @UpdateMode int default 1)
    begin
    
        declare @ProjectIdPosition int;
        select @ProjectIdPostion = Position
        from t
        where ProjectId = @ProjectId;
    
        if (@UpdateMode < @ProjectIdPosition)  -- Moving up the list
            update t
                set position = (case when position < @UpdateMode
                                     then position
                                     when position < @ProjectIdPosition
                                     then position + 1
                                     when ProjectId = @ProjectId
                                     then @UpdateMode
                                     when position
                                end);
        else if @UpdateMode > @ProjectIdPosition  -- Moving down the list
            update t
                set position = (case when position < @ProjectIdPostion
                                     then position
                                     when position < @UpdateMode
                                     then position - 1
                                     when ProjectId = @ProjectId
                                     then @UpdateMode
                                     else position
                                end);
    end;
    
    create procedure update\u project\u order(@projectd int,@UpdateMode int default 1)
    开始
    声明@projectdpositionint;
    选择@projectdposition=Position
    从t
    其中ProjectId=@ProjectId;
    if(@UpdateMode<@projectdPosition)--向上移动列表
    更新t
    设置位置=(位置<@UpdateMode时的情况
    然后定位
    当位置<@投影位置
    然后位置+1
    当ProjectId=@ProjectId时
    然后@UpdateMode
    当位置
    (完),;
    否则,如果@UpdateMode>@ProjectdPosition--向下移动列表
    更新t
    设置位置=(位置小于投影位置时的情况
    然后定位
    当位置<@UpdateMode
    然后是位置-1
    当ProjectId=@ProjectId时
    然后@UpdateMode
    其他位置
    (完),;
    结束;
    

    注意:我还没有测试过。这是关于如何实现它的一个想法。

    我认为这是两种不同的可能性,要么在列表中上移,要么在列表中下移。其余的只是位置上的算术运算,可以在单个update语句中完成

    create procedure update_project_order (@ProjectId int, @UpdateMode int default 1)
    begin
    
        declare @ProjectIdPosition int;
        select @ProjectIdPostion = Position
        from t
        where ProjectId = @ProjectId;
    
        if (@UpdateMode < @ProjectIdPosition)  -- Moving up the list
            update t
                set position = (case when position < @UpdateMode
                                     then position
                                     when position < @ProjectIdPosition
                                     then position + 1
                                     when ProjectId = @ProjectId
                                     then @UpdateMode
                                     when position
                                end);
        else if @UpdateMode > @ProjectIdPosition  -- Moving down the list
            update t
                set position = (case when position < @ProjectIdPostion
                                     then position
                                     when position < @UpdateMode
                                     then position - 1
                                     when ProjectId = @ProjectId
                                     then @UpdateMode
                                     else position
                                end);
    end;
    
    create procedure update\u project\u order(@projectd int,@UpdateMode int default 1)
    开始
    声明@projectdpositionint;
    选择@projectdposition=Position
    从t
    其中ProjectId=@ProjectId;
    if(@UpdateMode<@projectdPosition)--向上移动列表
    更新t
    设置位置=(位置<@UpdateMode时的情况
    然后定位
    当位置<@投影位置
    然后位置+1
    当ProjectId=@ProjectId时
    
    Create  Proc update_project_order (@ID Int, @NewPosition Int = 1)
    As
    
    Declare @OldPosition Int,
            @Direction Int
    
    Select  @OldPosition = Position
    From    tableName
    Where   ID = @ID
    
    Set     @Direction =    Case 
                            When    @OldPosition < @NewPosition Then 0
                            When    @OldPosition > @NewPosition Then 1
                            Else    -1
                            End
    
    Update  t
    Set     Old_Pos =   Position,
            Position =  Case
                        When    ID = @ID Then @NewPosition
                        When    @Direction = 0 And 
                                Position Between @OldPosition And @NewPosition Then Position - 1
                        When    @Direction = 1 And 
                                Position Between @NewPosition And @OldPosition Then Position + 1
                        Else    Position
                        End
    From    tableName t
    
    Create Procedure UPDATE_PROJECT_ORDER (@ID int,@Posi int) as
    begin
    
    Select Cast(ID as int) as ID,POSITION,Identity(int ,1,1) as NewPos
    into #tmp
    from Project
    where POSITION<=@Posi 
    order by POSITION
    
    Select Cast(ID as int) as ID,POSITION,Identity(int ,1,1)   as NewPos
    into #tmp2
    from Project
    where POSITION>=@Posi 
    order by POSITION
    
    
    
    Update Project set Project.POSITION=#tmp.NewPos 
    from #tmp 
    where #tmp.ID=Project.ID
    
    Update Project set Project.POSITION=#tmp2.NewPos + @Posi
    from #tmp2 
    where #tmp2.ID=Project.ID
    
    
    Update Project set POSITION=@Posi where ID=@ID
    
    Drop table #tmp
    Drop table #tmp2
    end
    
    CREATE Proc UPDATE_PROJECT_ORDER 
    (
        @ProjectID      As INT, 
        @StartPosition  As INT,
        @EndPosition    As INT
    ) As
    
    ;With
      cteProjectOld As
    (
        SELECT  ID, 
                POSITION,
                Case WHEN POSITION = @StartPosition 
                    THEN @EndPosition 
                    ELSE POSITION       END As TempPosition,
                Case WHEN POSITION = @StartPosition 
                    THEN 1 
                    ELSE 0              END As Moved
        FROM    PROJECT
    )
    , cteProjectNew As
    (
        SELECT  *,
                ROW_NUMBER() OVER(PARTITION BY ID ORDER BY TempPosition, Moved) As NewPosition
        FROM    cteProjectOld
    )
    UPDATE  cteProjectNew
    SET     POSITION = NewPosition
    WHERE   ID = @ProjectID