维护数据库表行的排序顺序

时间:2008-12-29 19:30:59

标签: database-design

假设我在数据库表中包含有关每行中新闻文章的信息。该表有一个整数“排序”列,用于指定文章在网站上的显示顺序。如何最好地实施和维护此排序顺序。

我想避免的问题是编号为1,2,3,4,...,100的文章,当文章编号50突然变得有趣时,它的排序编号设置为1,然后它们之间的所有文章必须他们的排序数量增加了一个。

当然,将初始排序数设置为100,200,300,400等会留下一些移动空间,但在某些时候它会破裂。

有没有正确的方法来实现这一点,也许是一种完全不同的方法?


添加-1

所有文章标题都显示在链接到内容的列表中,因此所有已排序的项目都会立即显示。

添加-2

项目不一定移到列表顶部;任何项目都可以放在有序列表中的任何位置。

12 个答案:

答案 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)

项目不一定移到列表顶部,任何项目都可以放在有序列表中的任何位置。

相关问题