如何使用SQL重新排序行(不是交换)

use*_*797 3 t-sql sql-server

我需要重新排序表中的项目,如以下示例所示:

Original:
Id    Pos (int)
---------
a     1
b     2
c     3
d     4
e     5

I need this result after moving d to the second row:
Id    Pos (int)
---------
a     1
b     3
c     4
d     2
e     5
Run Code Online (Sandbox Code Playgroud)

如您所见,它不是一个简单的交换,我需要在插入位置后将位置增加1,并在插入之前保留行.我试着这样解决它:

UPDATE [Table] SET Pos = 2 WHERE Id = 'd'

MERGE INTO [Table] T USING
(
    SELECT ROW_NUMBER() OVER(ORDER BY Pos) AS Position, Id FROM [Table]
) S
ON T.Id = S.Id
WHEN MATCHED THEN UPDATE SET Pos = S.Position;
Run Code Online (Sandbox Code Playgroud)

但是在更新后,两行具有相同的位置.它可能无法正确排序.

您可以使用以下脚本生成示例数据:

CREATE TABLE [Table] (
  Id char NOT NULL,
  Pos int NOT NULL,
  CONSTRAINT [PK_Table_Id] PRIMARY KEY CLUSTERED ([Id])
)
GO
INSERT INTO [Table] (Id, Pos) VALUES ('a', 1),('b', 2),('c', 3),('d', 4),('e', 5)
Run Code Online (Sandbox Code Playgroud)

Twi*_*les 7

DECLARE @id CHAR(1) = 'd';
DECLARE @newpos INT = 2;
DECLARE @oldpos INT;

BEGIN TRANSACTION
  SELECT @oldpos = Pos FROM Table WHERE id = @id;
  IF @newpos < @oldpos 
    UPDATE #Table SET Pos = Pos + 1 
     WHERE Pos >= @newpos AND Pos < @oldpos;
  ELSE
    UPDATE #Table SET Pos = Pos - 1 
     WHERE Pos >= @newpos AND Pos > @oldpos;

  UPDATE #Table SET Pos = @newpos
   WHERE Id = @id;
COMMIT TRANSACTION
Run Code Online (Sandbox Code Playgroud)