Sql server 在数据库表中使用排序顺序列

Sql server 在数据库表中使用排序顺序列,sql-server,database,sorting,Sql Server,Database,Sorting,比如说,我在购物网站的数据库中有一个产品表,用来保存商店产品的描述、价格等。让我的客户能够重新订购这些产品的最有效方式是什么 我创建了一个Order列(整数)用于对记录进行排序,但这给了我一些性能方面的麻烦,因为我使用原始方法在实际需要更改的记录之后更改每个记录的顺序。例如: Id Order 5 3 8 1 26 2 32 5 120 4 现在,如何将ID=26的记录顺序更改为3 我所做的是创建一个过程来检查目标顺序(3)中是否有记录,如果没有,则更新行

比如说,我在购物网站的数据库中有一个
产品
表,用来保存商店产品的描述、价格等。让我的客户能够重新订购这些产品的最有效方式是什么

我创建了一个
Order
列(整数)用于对记录进行排序,但这给了我一些性能方面的麻烦,因为我使用原始方法在实际需要更改的记录之后更改每个记录的顺序。例如:

Id    Order
5     3
8     1
26    2
32    5
120   4
现在,如何将ID=26的记录顺序更改为3

我所做的是创建一个过程来检查目标顺序(3)中是否有记录,如果没有,则更新行的顺序(ID=26)。如果目标顺序中有一条记录,则过程会自动执行,并将该行的ID以
目标顺序+1
作为参数发送

这会导致在我要更改以腾出空间的记录之后更新每个记录:

Id    Order
5     4
8     1
26    3
32    6
120   5
那么,一个更聪明的人会怎么做呢

  • 我使用SQLServer2008R2
编辑:

我需要一个项目的order列足以进行排序,而不涉及辅助键。订单列本身必须为其记录指定唯一的位置


除此之外,我想知道是否可以实现类似链表的功能:使用“下一个”列而不是“顺序”列来保留下一个项目ID。但是我不知道如何编写查询,以正确的顺序检索记录。如果有人对这种方法也有想法,请与我们分享。

我过去使用过的一种解决方案是使用“权重”而不是“顺序”,并取得了一些成功。重量是显而易见的,一件物品越重(即:数字越低)沉入底部,越轻(数字越高)上升到顶部

如果我有多个相同重量的物品,我假设它们具有相同的重要性,并按字母顺序排列

这意味着您的SQL将如下所示:

ORDER BY 'weight', 'itemName'
希望有帮助

Update product set order = order+1 where order >= @value changed
虽然随着时间的推移,您的订单中的“空格”会越来越大,但它仍然会“排序”

这将在一条语句中向正在更改的值和其后的每个值添加1,但上述语句仍然为真。越来越大的“空格”将以您的顺序形成,可能会超过INT值

考虑到无空间的需求,备选解决方案:

想象一个过程:updatesortororder,参数为@NewOrderVal、@IDToChange、@OriginalOrderVal

两步流程,取决于新/旧订单在排序中是上移还是下移

If @NewOrderVal < @OriginalOrderVal --Moving down chain 

--Create space for the movement; no point in changing the original 
    Update product set order = order+1 
    where order BETWEEN @NewOrderVal and @OriginalOrderVal-1;

end if

If @NewOrderVal > @OriginalOrderVal --Moving up chain

--Create space  for the momvement; no point in changing the original  
  Update product set order = order-1 
  where order between @OriginalOrderVal+1 and @NewOrderVal
end if

--Finally update the one we moved to correct value

    update product set order = @newOrderVal where ID=@IDToChange;
If@NewOrderVal<@OriginalOrderVal--向下移动链
--为运动创造空间;没有必要改变原作
更新产品集订单=订单+1
其中@NewOrderVal和@OriginalOrderVal-1之间的顺序;
如果结束
如果@NewOrderVal>@OriginalOrderVal--向上移动链
--为运动创造空间;没有必要改变原作
更新产品集订单=订单-1
其中@OriginalOrderVal+1和@NewOrderVal之间的顺序
如果结束
--最后更新一个我们移动到正确的值
更新产品集订单=@newOrderVal,其中ID=@IDToChange;

关于最佳做法;我所处的大多数环境通常需要按类别分组并按字母顺序排序或根据“销售人气”排序,因此无需提供用户定义的排序。

使用基本程序(以及其他地方)使用的老技巧:将订单列中的数字跳转10或其他方便的增量。然后,您可以在两个现有数字(相隔10行)之间插入一行(如果幸运的话,最多可以插入9行)。或者,您可以将第370行移动到565行,而不必从570向上更改任何行。

这非常简单。你需要有“基数洞”

结构:您需要有两列:

  • pk=32位整数

  • 顺序=64位bigint(bigint,不是DOUBLE!!!)

  • 插入/更新

  • 插入第一条新记录时,必须设置
    order=round(max\u bigint/2)

  • 如果在表的开头插入,则必须设置
    order=round(“第一条记录的顺序”/2)

  • 如果在表格末尾插入,则必须设置
    order=round(“max\u bigint-order of last record”/2)

  • >P>如果插入中间,则必须设置<代码>订单=回合(“2”之后的记录前顺序)< /代码>

    这种方法有很大的基数。若您有约束错误,或者您认为您的基数很小,那个么您可以重新生成订单列(规范化)

    在规范化的最大化情况下(使用此结构),您可以在32位中有“基数孔”

    这是非常简单和快速


    记住不要重复!!!只有整数阶才是精度值

    我目前正在开发一个需要排序的树状结构数据库。我使用一种链接列表方法,它将在客户端(而不是数据库)上排序。也可以通过递归查询在数据库中进行排序,但这对于本项目来说不是必需的

    我制作了这个文档,描述了我们将如何实现排序顺序存储,包括postgresql中的一个示例。请随时发表评论


    这里是一种使用公共表表达式(CTE)的替代方法

    这种方法尊重SortOrder列上的唯一索引,并将关闭排序顺序序列中可能由早期删除操作留下的任何间隙

    /* For example, move Product with id = 26 into position 3 */
    DECLARE @id int = 26
    DECLARE @sortOrder int = 3
    
    
    ;WITH Sorted AS (
        SELECT  Id,
                ROW_NUMBER() OVER (ORDER BY SortOrder) AS RowNumber
        FROM    Product
        WHERE   Id <> @id
    )
    
    UPDATE  p
    SET     p.SortOrder = 
            (CASE 
                WHEN p.Id = @id THEN @sortOrder
                WHEN s.RowNumber >= @sortOrder THEN s.RowNumber + 1
                ELSE s.RowNumber
            END)
    FROM    Product p
            LEFT JOIN Sorted s ON p.Id = s.Id 
    
    /*例如,将id=26的产品移动到位置3*/
    声明@id int=26
    声明@sortOrder int=3
    ;排序为(
    选择Id,
    (按排序器排序)上的行号()作为行号
    从产品
    其中Id@Id
    )
    更新p
    设置p.SortOrder=
    (案例
    当p.Id