更新事物列表而不触及每个条目
我在数据库中有一个用户应该能够订购的列表。
itemname| order value (int)
--------+---------------------
salad | 1
mango | 2
orange | 3
apples | 4
从数据库加载时,我只需按 order_value 排序
。
通过拖放,他应该能够移动苹果
,使其出现在列表的顶部。
itemname| order value (int)
--------+---------------------
apples | 4
salad | 1
mango | 2
orange | 3
好的。所以现在我必须在内部更新每个列表项!如果列表有 20 或 100 个项目,那么对于简单的拖动操作来说,这就是大量更新。
itemname| order value (int)
--------+---------------------
apples | 1
salad | 2
mango | 3
orange | 4
我宁愿只用一次更新来做到这一点。我想到的一种方法是“内部订单”是否是一个 double 值。
itemname| order value (double)
--------+---------------------
salad | 1.0
mango | 2.0
orange | 3.0
apples | 4.0
因此,在拖放操作之后,我指定 apples
的值小于它出现在前面的项目:
itemname| order value (double)
--------+---------------------
apples | 0.5
salad | 1.0
mango | 2.0
orange | 3.0
..并且如果一个项目被拖到中间某处,它的order_value
比它后面出现的那个大。这里我将 orange
移动到 salad
和 mango
之间:
itemname| order value (double)
--------+---------------------
apples | 0.5
salad | 1.0
orange | 1.5
mango | 2.0
关于更好的方法来做到这一点有什么想法吗?
I have a list in a database that the user should be able to order.
itemname| order value (int)
--------+---------------------
salad | 1
mango | 2
orange | 3
apples | 4
On load from the database, I simply order by order_value
.
By drag 'n drop, he should be able to move apples
so that it appears at the top of the list..
itemname| order value (int)
--------+---------------------
apples | 4
salad | 1
mango | 2
orange | 3
Ok. So now internally I have to update EVERY LIST ITEM! If the list has 20 or 100 items, that's a lot of updates for a simple drag operation.
itemname| order value (int)
--------+---------------------
apples | 1
salad | 2
mango | 3
orange | 4
I'd rather do it with only one update. One way I thought of is if "internal Order" is a double
value.
itemname| order value (double)
--------+---------------------
salad | 1.0
mango | 2.0
orange | 3.0
apples | 4.0
SO after the drag n' drop operation, I assign apples
has a value that is less than the item it is to appear in front of:
itemname| order value (double)
--------+---------------------
apples | 0.5
salad | 1.0
mango | 2.0
orange | 3.0
.. and if an item is dragged into the middle somewhere, its order_value
is bigger than the one it appears after .. here I moved orange
to be between salad
and mango
:
itemname| order value (double)
--------+---------------------
apples | 0.5
salad | 1.0
orange | 1.5
mango | 2.0
Any thoughts on better ways to do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
假设
@old
是苹果旧位置的值 4,而@new
是新位置 1。我使用 MySQL 5.1.52 在示例数据上测试了这一点它有效。如果您需要将较早的条目移至较晚的条目,或将中间的条目移至较晚的条目等,则相同的 SQL 也适用。只需设置
@old
和@new
的值即可。Suppose
@old
is the value 4 for the old position of apples, and@new
is the new position 1.I used MySQL 5.1.52 to test this on your example data and it works. The identical SQL also works if you need to move an early entry to be later, or move one in the middle, etc. Just set the values of
@old
and@new
.我最终使用了 邻接表。我当时并不知道这件事。
I ended up using an adjacencies table. I didn't know about it at the time.
我不确定这是否算作一种解决方案,但您实际上并不需要为每一行进行一次更新。如果你将 'foo' 从位置 4 移动到位置 1,
即使你从位置 1000 移动到 500,或者从 500 移动到 1000,你也只是做同样数量的更新(尽管你自然需要翻转它) ),您只需将所有受影响的行批量移动加或减一
I'm not sure if this counts as a solution, but you don't literally need to do one update for every row. If you move 'foo' from position 4 to position 1, you just do
It's the same number of updates even if you're moving from position 1000 to 500, or from 500 to 1000 (although you'll need to flip it, naturally), you just need to mass shift all the affected rows plus or minus one
您可以在单个 Update 语句中执行此操作,如下所示:
显然,您可以将
apples
替换为所选值。但是,我认为这种类型的排序最好在客户端应用程序中完成,而不是在数据库中完成。You can do it in a single Update statement like so:
You would obviously replace
apples
with the selected value. However, I would think that this type of sorting would best done in the client application rather than in the database.如果您使用的是 SQL Server,您可以使用链接列表表示和 CTE 来完成此操作。我不知道 mysql 是否支持 CTE...
这会产生以下前后结果:
If you were using SQL Server uou could do this using a linked-list representation and CTEs. I don't know whether mysql supports CTEs though...
This produces the following before and after results:
我想您的表上有一个主键,即
id
列。这两个语句应该可以。
如果您没有 id,请使用 itemname 代替。
I suppose you have a primary key on your table, an
id
column.These two statements should do.
If you don't have an id, use itemname instead.
正如之前所建议的,除非您必须向所有用户显示给定用户正在影响的当前订单,否则我建议您首先在客户端中处理这个问题(有很多方法可以解决这个问题),然后,根据用户操作(例如,按“我完成”按钮),您可以使用您选择存储在客户端中的结构中的最终顺序更新数据库中的行。
您可以使客户端中的代码变得尽可能复杂,以尽量减少数据库中需要更新的行数:在某些情况下,您可能只需要插入一行(如果用户插入列表末尾的新项目);在许多情况下,您可能需要更新两行(如果用户只是交换两个连续的项目)。根据需要更新的行数,最糟糕的情况是所有行(您可以设计一种算法,仅检测需要更新的行并只更新这些行)。您可以选择是否值得这样做或只是发布所有行的更新。
最重要的是,您不需要更新数据库中的所有行,这种情况只是许多可能的情况之一。有些数据库允许批量更新(名称可能因数据库而异),这不会很昂贵。
As has been suggested previously, and unless you have to show to all the users the current order that a given user is affecting, I would suggest that you treat this in the client first (there are many ways of solving this), and then, based on a user action (pressing the "I am done" button, for example) you update the rows in the database with the final order from the structure that you have chosen to store in the client.
You can make the code in the client as complex as you want to try to minimize the number of rows that need to be updated in the database: in some case, you may only need to insert one row (if the user inserts a new item at the end of the list); in many cases you may need to update two rows (if the user just swaps two consecutive items). The worst scenario as per the number of rows that need to be updated, is all the rows (you can device an algorithm that will only detect the rows that need to be updated and just update those). The choice is yours whether it is worth doing this or just issuing an update of all the rows.
The bottom line is that you do not need to update all the rows in the database, that situation is just one of the many possible scenarios. Some databases allow update in bulk (the name may vary from one database to another) and this will not be very expensive.
如果列只是指定行的顺序,我认为使用 0 和负数没有任何问题。
If the column simply specifes the order of the rows, I don't see anything wrong with using 0 and negatives.