【问题标题】:How to rearrange "sort order" column after changing the rows' sort order更改行的排序顺序后如何重新排列“排序顺序”列
【发布时间】:2019-02-22 05:01:45
【问题描述】:

我有一个包含很多行的表格,并且一个名为“order”的列从 1 到 XX 取决于我的表格中有多少行。

问题是,如果我想将带有“订单”1 的行移动到位置 3,我需要其他行的另一个“订单”来重新排列自己。

例如,如果我用“3”移动“订单”1,那么后面的所有数字都必须增加1,第二个现在必须是“订单”1。

我希望我是清楚的。

感谢您的帮助!

编辑/样本数据

Name   |  Order
Line 1 |  1
Line 2 |  2
Line 3 |  3
Line 4 |  4

如果我用 4 而不是 1 更新“第 1 行”的顺序,我希望其他人的顺序更新!

Name   |  Order
Line 2 |  1
Line 3 |  2
Line 4 |  3
Line 1 |  4

如果我用 1 更新“第 4 行”的顺序也是一样!

Name   |  Order
Line 4 |  1
Line 1 |  2
Line 2 |  3
Line 3 |  4

如果我用 2 来更新“第 3 行”的顺序也是一样的!

Name   |  Order
Line 1 |  1
Line 3 |  2
Line 2 |  3
Line 4 |  4

【问题讨论】:

  • 您能提供一些示例数据并期待结果吗?
  • 不清楚,因为我不知道你所说的“移动”一行是什么意思。 SQL 表中的记录在所有意图和目的上都是无序的。您能否提供一些示例数据来解释您的问题?
  • 这听起来很奇怪,但是您是否考虑过为这个order 列使用浮点数或其他十进制 支持类型?它显然仍然可以定义一个订单,但您可以计算一个新的订单值 ((preceding row + succeeding row)/2),而无需重新编号其他行。 (如果您认为有必要,您可以选择定期对所有行重新编号,以将它们全部恢复为 int 值)
  • 懒惰、缓慢、简单的方法:一次移动一个位置,通过在相邻(顺序)元素之间交换顺序
  • 我刚刚用示例数据更新了我的问题并期待结果@D-Shih

标签: sql sql-server sorting tsql


【解决方案1】:

试试这个方法

DECLARE @tbl TABLE([Name] VARCHAR(100),[Order] INT);
INSERT INTO @tbl VALUES
 ('Line 1',1) 
,('Line 2',2) 
,('Line 3',3)
,('Line 4',4);

DECLARE @OldPos INT=3, @NewPos INT=2;

WITH cte AS
(
    SELECT [Name]
          ,[Order]
          ,ROW_NUMBER() OVER(ORDER BY CASE WHEN [Order]=@OldPos 
                                           THEN CAST(@NewPos AS FLOAT) 
                                                + CASE WHEN @OldPos<@Newpos 
                                                       THEN 0.5 ELSE -0.5 END 
                                           ELSE CAST([Order] AS FLOAT) END) AS ComputedPos 
    FROM @tbl 
)
UPDATE cte SET [Order] = ComputedPos
WHERE [Order]<>ComputedPos;

SELECT * FROM @tbl ORDER BY [Order];

这使用了一个可更新的 CTEDamian_The_Unbeliever 的评论给了我这个想法,而无需更改订单的数据类型。

函数ROW_NUMBER 将在其OVER 子句中进行一些计算。如果[Order] 具有正确的输入值,我们将通过将0.5-0.5 添加到新位置来设置新邻居之间的新位置。这取决于您移动行的方向

【讨论】:

  • @SalmanA 真的,谢谢你的提示。添加WHERE [Order]&lt;&gt;ComputedPos 作为最后一行
【解决方案2】:

您可以使用CASE 声明:

UPDATE ...
SET [Order] = [Order] + CASE
  WHEN [Order] = @OLDPOS THEN @NEWPOS - @OLDPOS
  WHEN @NEWPOS > @OLDPOS AND [Order] > @OLDPOS AND [Order] <= @NEWPOS THEN -1
  WHEN @NEWPOS < @OLDPOS AND [Order] < @OLDPOS AND [Order] >= @NEWPOS THEN 1
  ELSE 0
END

Here are some tests

可以通过在上面添加ROW_NUMBER() 来修复间隙和重叠。

Some moar tests

【讨论】:

  • 但这也会更新所有行 ;-) 此外,我们不知道它是否只是排序顺序,或者 OP 是否需要从 1 到 n 编号的行没有间隙...
  • @Shungo 只需添加一个 where 子句 WHERE [Order] BETWEEN smallerof(@Old, @new) AND greaterof(@Old, @new)。但是,是的,它不能解决差距问题。
  • 感谢您的帮助!是的,我总是需要订单从 1 到 N 没有间隙!!
  • @MatthieuRigaux 再三考虑......如果它们已经存在,它不会修复间隙/重叠,它只会移动它们。 ROW_NUMBER() 方法将是自我纠正的。我可能可以将上面的内容转换为ROW_NUMBER(),但已经有了答案。
  • 您的解决方案对我来说很好,因为我的列表中不会有空白。我将在表格末尾自动添加新行,并在删除时更新(如果需要)下面其他行的顺序以填补空白!非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2021-04-23
相关资源
最近更新 更多