我如何存储订单?

时间:2009-02-13 18:06:51

标签: mysql sorting database-design

我有一个应用程序,其中包含任务,您可以重新排序它们。现在我想知道如何最好地存储它们。我是否应该为ordernumber设置colomn并在每次更改时重新计算所有这些?请告诉我一个不需要我更新所有订单号的版本,因为这非常耗时(从执行的角度来看)。

如果我必须将一个放在订单的最顶层,然后将其拖到底部,那么这一点尤其糟糕。

  • 姓名(订单号)

-

  • 1例(1)
  • 2示例(2)
  • 3示例(3)
  • 4例(4)
  • 5例(5)

-

  • 2例(1)*
  • 3例(2)*
  • 4例3(*)*
  • 5例(4)*
  • 1例(5)*

*必须在数据库中更改

也可能因某些任务被删除而被删除

6 个答案:

答案 0 :(得分:14)

您可以将订单保留为文字,并使用词汇排序:

1. A
2. Z

添加任务:

1. A
3. L
2. Z

添加更多:

1. A
4. B
3. L
2. Z

在1和4之间移动2:

1. A
2. AL
4. B
3. L

您一次只更新一条记录:只需在第一条记录之间取一个平均字母:如果您放在AC之间,则可以B,如果您放在ALGJALILFG之间,您可以ALH

现有字母旁边的字母与Z旁边的字母串联。 I. e。如果您需要在ABHDFGACSD F之间加注,则将其计入ABHAB(Z+)之间,并写AB(letter 35/2),即ABP

如果您的字符串长度不足,您可能总是执行完整的重新排序。

<强>更新

您还可以将数据保存为链接列表。

请参阅我的博客中有关如何在MySQL中执行此操作的文章:

简而言之:

/* This just returns all records in no particular order */

SELECT  *
FROM    t_list

id      parent
------- --------
1       0
2       3
3       4
4       1

/* This returns all records in intended order */

SELECT  @r AS _current,
        @r := (
        SELECT  id
        FROM    t_list
        WHERE   parent = _current
        )
FROM    (
        SELECT  @r := 0
        ) vars,
        t_list

_current id
-------  --------
0        1
1        4
4        3
3        2

移动项目时,您最多需要更新4行。

这似乎是保持经常更新的有序列表的最有效方法。

答案 1 :(得分:9)

通常情况下,我会按照你的建议添加一个名为'Ordinal'或'PositionOrdinal'之类的int或smallint列,并提到你提到的确切警告 - 每次单个记录时都需要更新潜在的大量记录被重新订购。

好处是,给定特定任务的密钥和该任务的新位置,移动项目的代码只是两个陈述:

UPDATE `Tasks` SET Ordinal= Ordinal+1 WHERE Ordinal>=@NewPosition
UPDATE `Tasks` SET Ordinal= @NewPosition WHERE TaskID= @TaskID

对于双重链接列表或词汇顺序还有其他建议。两者都可以更快,但代价是更复杂的代码,只有在同一组中有批次项目时,性能才会重要。

性能或代码复杂性是否更重要取决于您的情况。如果您有数百万条记录,那么额外的复杂性可能是值得的。但是,我通常更喜欢更简单的代码,因为用户通常只能手动订购小型列表。如果列表中没有那么多项,则额外更新无关紧要。这通常可以处理数千条记录,而不会对性能产生任何明显影响。

要更新的示例要记住的一件事是该列仅用于排序,而不是直接显示给用户。因此,当将项目从顶部拖动到底部时,如图所示,您需要更改的唯一内容是一条记录。你将第一个位置留空并不重要。这意味着有足够的潜力可以通过足够的重新排序来溢出整数排序,但让我再说一遍:用户通常只能手动订购小型列表。我从未听说过这种风险实际上会导致问题。

答案 2 :(得分:2)

在你的答案中,我想出了一个如下混合物:

说我们有:

  • 1例(1)
  • 2示例(2)
  • 3示例(3)
  • 4例(4)
  • 5例(5)

现在,如果我在4到5之间排序,它将如下所示:

  • 2示例(2)
  • 3示例(3)
  • 4例(4)
  • 1例(4.5)
  • 5例(5)

现在又在1到5之间

  • 3示例(3)
  • 4例(4)
  • 1例(4.5)
  • 2例(4.75)
  • 5例(5)

它总是需要数字之间差异的一半

我希望有效的方法请纠正我;)

答案 3 :(得分:1)

我们使用数据库中的Sequence列进行。

我们使用稀疏编号(例如10,20,30,...),因此我们可以在现有值之间“插入”一个。如果相邻的行具有连续的数字,我们会重新编号我们可以的最小行数。

您可能使用十进制数字 - 取与您插入位置相邻的行的序列号的平均值,然后您只需更新“被移动”的行

答案 4 :(得分:1)

这不是一个容易的问题。如果您的可排序元素数量很少,我只会将它们全部重置为新订单。

否则,“测试和设置”似乎只需要修改已修改的记录就可以完成更多的工作。

您可以将此工作委托给客户端。让客户端维护旧排序和新排序并确定应该更新哪一行[sort-order] - 然后将这些元组传递给PHP-mySQL接口。

您可以通过以下方式增强此方法(需要浮点数):

  1. 如果列表中的所有可排序元素根据它们在列表中的位置初始化为排序顺序,请将每个元素的排序顺序设置为类似[row-order] = row [sort-订单* K]其中K是某个数字&gt;您希望列表重新排序的平均次数。 O(N),N =元素数量,但插入容量增加至少N * K,每对现有元素之间至少有K个开放时隙。

  2. 然后,如果要在另外两个元素之间插入一个元素,就像将其排序顺序更改为&gt;一样简单。较低的元素和&lt;上层。如果元素之间没有“空间”,您可以简单地重新应用前一段中提出的“传播”算法(1)。 K越大,应用的频率越低。

  3. K算法将有选择地应用于PHP脚本,而新的排序顺序的选择将由客户端完成(可能是Javascript)。

答案 5 :(得分:0)

我建议在数据库中有一个订单栏。重新排序对象时,在您重新排序的对象和具有相同订单值的对象之间交换数据库中的订单值,这样您就不必重新加载整个行集。

希望有道理......当然,这取决于您重新订购的规则。