Şaf*_*Gür 31 database sql-server sorting
假设我Product在购物网站的数据库中有一张桌子,用于保存商店产品的描述,价格等.使我的客户能够重新订购这些产品的最有效方法是什么?
我创建了一个Order用于排序记录的列(整数),但由于我在实际需要更改之后用于更改每个记录顺序的原始方法,这让我对性能产生了一些麻烦.一个例子:
Id Order
5 3
8 1
26 2
32 5
120 4
Run Code Online (Sandbox Code Playgroud)
现在我该怎么做才能将记录的顺序更改ID=26为3?
我所做的是创建一个程序,检查目标订单中是否有记录(3),如果没有,则更新行的顺序(ID = 26).如果目标顺序中有记录,则该过程将自行发送该行的ID target order + 1作为参数.
这导致在我想要改变以便腾出空间之后更新每一条记录:
Id Order
5 4
8 1
26 3
32 6
120 5
Run Code Online (Sandbox Code Playgroud)
那么聪明人会做些什么呢?
编辑:
我需要一个项目的订单列足以进行排序,而不涉及二级密钥.单独的订单列必须为其记录指定唯一的位置.
除此之外,我想知道我是否可以实现链接列表之类的内容:"下一个"列而不是"订单"列以保留下一个项目ID.但我不知道如何编写以正确顺序检索记录的查询.如果有人也对这种方法有所了解,请分享.
xQb*_*ert 28
Update product set order = order+1 where order >= @value changed
Run Code Online (Sandbox Code Playgroud)
虽然随着时间的推移,你会在订单中获得越来越大的"空间",但它仍然会"排序"
这将在一个语句中将要更改的值和其后的每个值加1,但上述语句仍然为真.越大越大的"空格"将在您的订单中形成,可能达到超过INT值的程度.
希望没有空格的替代解决方案:
想象一个程序:UpdateSortOrder参数为@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;
Run Code Online (Sandbox Code Playgroud)
关于最佳做法; 我所经历的大多数环境通常都需要按类别分组并按字母顺序或基于"销售中的受欢迎程度"排序的内容,从而无需提供用户定义的排序.
使用BASIC程序(以及其他地方)使用的旧技巧:将订单列中的数字跳过10或其他一些方便的增量.然后,您可以在两个现有数字(相隔10个)之间插入一行(实际上,最多9行,如果您很幸运).或者,您可以将行370移动到565,而无需从570向上更改任何行.
小智 6
这很简单。你需要有“基数洞”。
结构:您需要有 2 列:
pk = 32 位整数
order = 64bit bigint (BIGINT, NOT DOUBLE!!!)
插入/更新L
当您插入第一条新记录时,您必须设置order = round(max_bigint / 2).
如果在表的开头插入,则必须设置order = round("order of first record" / 2)
如果在表尾插入,则必须设置order = round("max_bigint - order of last record" / 2)
如果在中间插入,则必须设置order = round("order of record before - order of record after" / 2)
这种方法有很大的基数。如果您有约束错误或者您认为基数较小,您可以重建订单列(标准化)。
在标准化的最大值情况下(使用此结构),您可以在 32 位中出现“基数空洞”。
非常简单快捷!
记住不要双重!只有 INT - 顺序才是精度值!
我过去使用的一种解决方案(取得了一些成功)是使用“重量”而不是“顺序”。重量很明显,较重的物品(即:数字越小)沉入底部,越轻(数字越大)则升至顶部。
如果我有多个重量相同的物品,我认为它们具有相同的重要性,并按字母顺序排列。
这意味着您的SQL将如下所示:
ORDER BY 'weight', 'itemName'
Run Code Online (Sandbox Code Playgroud)
希望能有所帮助。
这是使用公用表表达式 (CTE) 的另一种方法。
此方法尊重 SortOrder 列上的唯一索引,并将关闭排序顺序序列中可能已从早期 DELETE 操作中遗留下来的任何间隙。
/* 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
Run Code Online (Sandbox Code Playgroud)