假设我在数据库表中包含有关每行中新闻文章的信息。该表有一个整数“排序”列,用于指定文章在网站上的显示顺序。如何最好地实施和维护此排序顺序。
我想避免的问题是编号为1,2,3,4,...,100的文章,当文章编号50突然变得有趣时,它的排序编号设置为1,然后它们之间的所有文章必须他们的排序数量增加了一个。
当然,将初始排序数设置为100,200,300,400等会留下一些移动空间,但在某些时候它会破裂。
有没有正确的方法来实现这一点,也许是一种完全不同的方法?
添加-1 :
所有文章标题都显示在链接到内容的列表中,因此所有已排序的项目都会立即显示。
添加-2 :
项目不一定移到列表顶部;任何项目都可以放在有序列表中的任何位置。
答案 0 :(得分:10)
忘记正确 - 你要避免的问题不是什么大问题,而是只需要几个UPDATE语句,这取决于你的RDBMS(我假设Oracle并且你正在将文章“移动”到列表):
UPDATE Articles
SET sort_number = sort_number + 1
WHERE sort_number BETWEEN :new_sort_number and :current_sort_number - 1;
UPDATE Articles
SET sort_number = :new_sort_number
WHERE article_id = :article_id;
最大的警告是SET功能在所有RDBMS中都不起作用。
如果您真的想要考虑正确,请考虑根据数据结构重新思考问题 - 您可能会问的是如何在数据库中实现链接列表。
维护排序号列的另一种方法是维护父ID 列。这可以说是更正确的,因为它保留了数据的序列化,但缺点是查询数据不是很好或不高效(例如,想想Oracle中的CONNECT BY)。
如果问题是 best ,或许你想要考虑父ID 列的正确性,并通过派生排序号来对数据进行非规范化列的值,可能来自父ID 数据或第一个解决方案。
答案 1 :(得分:8)
如果我理解你的问题;我会使用包含某种类型的排名索引号的列。这个数字不一定是唯一的。您需要提出某种算法来计算排名。
然后只对排名列进行排序,使用辅助列来处理排名关系(可能是创建日期或其他内容)。
答案 2 :(得分:5)
在链表数据结构之后对表进行建模。摆脱“排序”列,而是有一个next_article_id列,指向后面的下一篇文章。然后,当您想要在第50位添加新文章时,您只需要更新文章#49以指向您的新文章,然后将您的新文章指向之前指向的第49条文章。
答案 3 :(得分:4)
(对不起英语。我正在学习)
很简单。你需要有"基数洞"
结构你需要有2列
1)pk = 32bit int
2)order = 64bit bigint(BIGINT,not DOUBLE !!!)
插入/更新
1)当您插入第一个新记录时,您必须设置order = round(max_bigint / 2)。
2)如果你在表格的开头插入,你必须设置order = round("第一个记录的顺序" / 2)
3)如果你在表格末尾插入,你必须设置order = round(" max_bigint - 最后一条记录的顺序" / 2)
4)如果你插入中间你必须设置order = round("记录顺序 - 记录顺序" / 2)
这种方法有很大的忠诚度。如果你有约束错误,或者你认为你有小基数,你可以重建订单栏(规范化)。
在规范化的最大化情况下(使用这种结构)你可以拥有"基数洞"在32位。
非常简单快捷!
记住没有双倍!!!只有INT - order是精度值!
答案 4 :(得分:1)
使用实数似乎是计算效率最高的选择。您可以通过将两行之间的距离加一半来在两个其他行之间移动一行。要在row1和row2之间移动newrow,请将newrow计算为newrow = row1 +(row2 - row1)/2.0。但是,由于浮点限制,此系列(使用双精度)将在53次迭代中收敛。所以最糟糕的情况是你只能进行53次插入(如果你不是总是在最后一次newrow和row2之间插入,那么更多)。这类似于留下间隙并填充它们的想法。进行更新的想法效率较低,但在一定数量的插入后不会中断。保持列索引可能会有所帮助。
答案 5 :(得分:1)
以Alkini的答案为基础(我会直接回复,但我暂时没有分数/特权)。仅当新的显示顺序小于新显示顺序时,该方法才有效。如果它是相反的方式那么你需要在另一个方向之间移动文章。
if(new_sort_number == current_sort_number)
Do nothing
if(new_sort_number< current_sort_number)
UPDATE Articles
SET sort_number = sort_number + 1
WHERE sort_number BETWEEN :new_sort_number and :current_sort_number - 1;
if(new_sort_number> current_sort_number)
UPDATE Articles
SET sort_number = sort_number - 1
WHERE sort_number BETWEEN :current_sort_number + 1 and :new_sort_number;
然后在任何一种情况下,更新已移动的文章。
UPDATE Articles
SET sort_number = :new_sort_number
WHERE article_id = :article_id;
希望能帮助其他人寻找广义的显示顺序更新算法。
答案 6 :(得分:0)
使用降序排序,即最高排序编号显示在顶部。
如果旧文章应放在列表的顶部,只需将其排序列设置为MAX(排序)+1。无需重新编号整个表格。
您的意见后更新:
将排序顺序更改为浮点数。如果文章的排序顺序在另外两篇文章之间重新排列,则新的Sort值设置为((上一篇文章的排序)+(下一篇文章的排序))/ 2.否则,将Sort设置为MAX + 1。
答案 7 :(得分:0)
我想避免的问题是 编号的文章 1,2,3,4,..,100
我建议您不要尝试将排序键作为主键,或者是唯一的。如果它们的键不唯一,则可以使用具有相同值的多个项目。您可能希望简单地使您的排序键成为简单的1-10级。
所以也许10级的东西会非常有趣,5级会很正常,1级会非常无聊。当某些东西变得无聊或更有趣时,只需向下或向上调整排序键的值。
答案 8 :(得分:0)
为了做到这一点,我们将行设置为递增整数,然后使用存储过程来移动项目。 proc需要两个args,即项目的当前索引,以及要将其移动到的新索引。它执行更新项目设置index = index + sign(@newidx - @oldidx),其中itemMax(@ newidx,@ oldidx)和itemMin(@ newidx,@ oldidx)之间的索引更新两者之间的项目,然后更新更改实际项目到新索引。这不是实际代码,仅来自内存。在我们的表中,我们有两列,id和索引,因此即使在同一个索引处最终有两个项目,我们也可以通过ID区分它们。这可以通过对要移动的项目进行更新并且索引为-1来规避,然后更新其余部分,最后将新项目-1移动到新索引。
答案 9 :(得分:0)
我会回答大多数人所说的答案,即你的表中应该有一个单独的列,其中包含记录的排序/兴趣值。如果你想在保持健壮的同时考虑某种时间参数,你可能想尝试在给定的时间段内合并一个数据“视图”。
即。每晚午夜,您都可以创建主表的表格视图,但只能使用过去2或3天的文章创建表格视图,然后严格按照该表格维护排序/兴趣计数。如果有人正在选择不在该表中的旧文章(例如从一周前开始),您可以随时将其插入当前视图中。通过这种方式,您可以获得年龄的效果。
重点是在表格上保持小指数,其中排序/利息值的插入和更新应保持相对较快。您应该只需要在创建视图期间预先支付复杂的连接,然后您可以保持平坦以优化过多的读取。在视图中你会有多少,几百,几千?每当有人提出请求时,都要尝试排序十万。
答案 10 :(得分:-1)
所有文章标题都显示在链接到内容的列表中,因此所有已排序的项目都会立即显示。
答案 11 :(得分:-1)
项目不一定移到列表顶部,任何项目都可以放在有序列表中的任何位置。