Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 对有序列表重新排序_Sql_Database Design - Fatal编程技术网

Sql 对有序列表重新排序

Sql 对有序列表重新排序,sql,database-design,Sql,Database Design,我有一个包含数据的SQL表 ProductList id order productname 79 1 name1 42 2 name2 67 3 somename 88 4 othername 99 5 XYZ 66 6 ABC 显示顺序非常不稳定,它会频繁更改,用户会添加或删除项目并重新排序项目 在不更新多个记录的情况下,我应该如何处理这种情况。示例:如果用户输入了一个介于1和2之间的新产品订单,我不想更新2下所有

我有一个包含数据的SQL表

ProductList 
id  order productname
79   1     name1
42   2     name2
67   3     somename
88   4     othername
99   5     XYZ
66   6     ABC
显示顺序非常不稳定,它会频繁更改,用户会添加或删除项目并重新排序项目


在不更新多个记录的情况下,我应该如何处理这种情况。示例:如果用户输入了一个介于1和2之间的新产品订单,我不想更新2下所有记录的顺序,如果有人将订单3切换到4,我不想更新3下的所有记录。

使用“orrible old trick Make Family(?)由旧的基本编码器制作-将订单设置为100、200、300,400等,然后您可以在需要时选择“中间”订单。这可能会变得混乱-如果您预计会有大量的重新排序,那么我建议您安排一项计划任务,以便不时对整个表的顺序值进行“重新排序”。

您有两个选项:

  • 使用UPDATE语句和/etc函数迭代行,以生成更新的订单值
  • 焦土:删除现有记录,插入相同的记录并保存更正的订单值

没有SQL功能可以简化这一过程,也没有简单的实际选项。

您可以使用链表进行排序(使用一些特殊的方法来识别头部)


插入是一次插入和一次更新。删除是一次删除和一次更新。一次移动需要三次更新。(当然,使用事务来确保链表不会中断。)

添加一个名为OrderDateTime的DATETIME列。使用此列(按降序)解析排序中的“关系”,并且仅在进行排序操作时更新它

例如,在您的示例中,假设所有行都具有昨天的OrderDateTime值

现在,要在1和2之间插入一个项目,您需要将它的Order值设置为2,OrderDateTime值设置为Now。当您从ProductList ORDER BY ORDER ASC中选择*时,OrderDateTime DESC新的2号项目将在现有项目之前排序

类似地,要交换项目4和5,您需要将项目5更新为订单为4,订单日期时间为now。它将成为更近的4项,并出现得更早


如果您试图在已经具有相同订单值的两个其他项目之间插入一个项目,则需要注意将OrderDateTime值差分开。

相同问题的第二个答案:


使用双字段进行排序,并分割要插入的两个值之间的差值。在任何标准的业务应用程序中,我都非常非常怀疑您是否会接近无法解决排序顺序差异的插入数。

您可以使用字符串代替无限多个数字。如果您想在“1”和“2”之间插入,请将其设置为“15”。

在我的示例中,我允许用户在巡更中重新排列步骤。我有一个名为STEP的列,他们可以更改它,我创建了一个名为STEP2的列。STEP2列将自动更新为与step相同的值。但当用户更改步骤时,我会按照建议的更改和原始顺序(步骤2)说明进行排序。在用户将步骤更新为新值后,我会保存到数据库中。然后我运行一个proc来重新排序这些步骤

程序是:

DECLARE @t StackTable

INSERT INTO @t(Id)
SELECT Id
FROM TourStops
WHERE TourIdRef = @tourId
ORDER BY [Step], [Step2] DESC

UPDATE TourStops
SET [Step] = t.Position, [Step2] = t.Position
FROM TourStops s join @t t on s.Id = t.Id

StackTable是一个UDT,有两列:Id和Position。位置是一个标识列。每次创建它时,它都从1开始,每添加一行就递增1。

根据Larry Lustig关于使用双精度的建议,我想到了这个。在一个有10K行的表上运行时,它运行得非常快。当然欢迎提出提高效率的建议

--- Note:
--- [Order] column is a value type of double
--- when inserting into MyTable, set [Order] to
--- MAX([Order])+10
CREATE PROCEDURE dbo.MoveUpLevel
(
    @MyTableID int
)
AS
BEGIN
SET NOCOUNT ON


DECLARE @LevelMe float
DECLARE @LevelMin float
DECLARE @LevelMax float
SELECT @LevelMe = [Order]
    FROM dbo.MyTable WITH (NOLOCK)
    WHERE MyTableID = @MyTableID
SELECT @LevelMin = MIN([Order])
      ,@LevelMax = MAX([Order])
    FROM dbo.MyTable WITH (NOLOCK)

--- Check if already at the top
IF @LevelMe = @LevelMin
    RETURN(0)

DECLARE @LevelAboveMe float
SELECT TOP 1 @LevelAboveMe = [Order]
    FROM dbo.MyTable WITH (NOLOCK)
    WHERE [Order] < @LevelMe
    ORDER BY [Order] DESC

DECLARE @LevelAboveMe2 float = 0
IF NOT @LevelAboveMe = @LevelMin
    SELECT TOP 1 @LevelAboveMe2 = [Order]
        FROM dbo.MyTable WITH (NOLOCK)
        WHERE [Order] < @LevelAboveMe
        ORDER BY [Order] DESC

-- calculate new level
SET @LevelMe = @LevelAboveMe2 + ((@LevelAboveMe - @LevelAboveMe2)/2)
-- store to DB
UPDATE dbo.MyTable
    SET [Order] = @LevelMe
    WHERE MyTableID = @MyTableID        

RETURN(0)
END
GO

CREATE PROCEDURE dbo.MoveDownLevel
(
     @MyTableID int
)
AS
BEGIN
SET NOCOUNT ON

DECLARE @LevelMe float
DECLARE @LevelMin float
DECLARE @LevelMax float
SELECT @LevelMe = [Order]
    FROM dbo.MyTable WITH (NOLOCK)
    WHERE MyTableID = @MyTableID
SELECT @LevelMin = MIN([Order])
      ,@LevelMax = MAX([Order])
    FROM dbo.MyTable WITH (NOLOCK)

--- Check if already at the bottom
IF @LevelMe = @LevelMax
    RETURN(0)

DECLARE @LevelBelowMe float
SELECT TOP 1 @LevelBelowMe = [Order]
    FROM dbo.MyTable WITH (NOLOCK)
    WHERE [Order] > @LevelMe
    ORDER BY [Order] ASC

DECLARE @LevelBelowMe2 float = @LevelMax + 10
IF NOT @LevelBelowMe = @LevelMax
    SELECT TOP 1 @LevelBelowMe2 = [Order]
        FROM dbo.MyTable WITH (NOLOCK)
        WHERE [Order] > @LevelBelowMe
        ORDER BY [Order] ASC

-- calculate new level
SET @LevelMe = @LevelBelowMe + ((@LevelBelowMe2 - @LevelBelowMe)/2)

-- store to DB
UPDATE dbo.MyTable
    SET [Order] = @LevelMe
    WHERE MyTableID = @MyTableID        

RETURN(0)
END
GO
——注意:
---[Order]列是双精度的值类型
---插入MyTable时,将[Order]设置为
---最大([订单])+10
创建过程dbo.MoveUpLevel
(
@MyTableID int
)
作为
开始
不计较
声明@LevelMe float
声明@LevelMin float
声明@LevelMax float
选择@LevelMe=[Order]
使用(NOLOCK)从dbo.MyTable
其中MyTableID=@MyTableID
选择@LevelMin=MIN([订单])
,@LevelMax=MAX([订单])
使用(NOLOCK)从dbo.MyTable
---检查是否已经在顶部
如果@LevelMe=@LevelMin
返回(0)
声明@leveloverme浮动
选择顶部1@leveloverme=[订单]
使用(NOLOCK)从dbo.MyTable
何处[订单]<@LevelMe
按[订单]说明订购
声明@leveloverme2 float=0
如果不是@leveloverme=@LevelMin
选择顶部1@leveloverme2=[订单]
使用(NOLOCK)从dbo.MyTable
何处[订单]<@leveloverme
按[订单]说明订购
--计算新水平
设置@LevelMe=@leveloverme2+(@leveloverme-@leveloverme2)/2)
--存储到数据库
更新dbo.MyTable
设置[顺序]=@LevelMe
其中MyTableID=@MyTableID
返回(0)
结束
去
创建过程dbo.MoveDownLevel
(
@MyTableID int
)
作为
开始
不计较
声明@LevelMe float
声明@LevelMin float
声明@LevelMax float
选择@LevelMe=[Order]
使用(NOLOCK)从dbo.MyTable
其中MyTableID=@MyTableID
选择@LevelMin=MIN([订单])
,@LevelMax=MAX([订单])
使用(NOLOCK)从dbo.MyTable
---检查是否已经在底部
如果@LevelMe=@LevelMax
返回(0)
声明@LevelBelowMe float
选择TOP 1@LevelBelowMe=[订单]
使用(NOLOCK)从dbo.MyTable
何处[订单]>@LevelMe
按[订单]订购ASC
声明@LevelBelowMe2 float=@LevelMax+10
如果不是@LevelBelowMe=@LevelMax
选择顶部1@LevelBelowMe2=[顺序]
使用(NOLOCK)从dbo.MyTable
其中[Order]>@LevelBelowMe
按[订单]订购ASC
--计算新水平
设置@LevelMe=@LevelBelowMe+(@LevelBelowMe2-@LevelBelowMe)/2)
--存储到数据库
更新dbo.MyTable
设置[顺序]=@LevelMe
其中MyTableID=@MyTableID
返回(0)
结束
去

没有计划的任务来“重新排序”订单,它必须是实时的。就像A所说的那样-从它们之间有很长距离的值开始。当你必须在中间插入东西时,插入