Reputation: 43852
In a particular application, a user is able to store widgets in a favorites list. Users and widgets each have their own IDs, so I devised a Favorites
table to store users' favorites:
+-----------+------------------+
| Field | Type |
+-----------+------------------+
| userid | int(11) unsigned |
| widgetid | int(11) unsigned |
| dateadded | int(11) unsigned |
+-----------+------------------+
This is all well and good, but now I want the user to be able to manually reorder the widgets in their favorites. Suddenly, the dateadded
column is unhelpful, since updating it would only allow a user to bump a widget to the front of the list.
Therefore, it would seem I need an index column instead:
+-----------+------------------+
| Field | Type |
+-----------+------------------+
| userid | int(11) unsigned |
| widgetid | int(11) unsigned |
| index | int(11) unsigned |
+-----------+------------------+
This way, to reorder columns, I can just manipulate the DB table like an array—pull out a row, renumber the others to "free" a slot, and reinsert the row. For example, to move the object at index 13
to index 5
, I would do the following:
SELECT * FROM Favorites WHERE `index` = 13;
DELETE * FROM Favorites WHERE `index` = 13;
UPDATE Favorites
SET `index` = `index` + 1
WHERE `index` >= 5 AND `index` < 13;
INSERT INTO Favorites (userid, widgetid, index) VALUES (<data from select>, 5);
However, this feels extremely hacky and very un-SQL, and I can't imagine the performance would be fantastic, either.
What is a "proper" solution to storing arbitrarily-reorderable data in a MySQL database?
Upvotes: 2
Views: 369
Reputation: 57401
I would use index values with some step e.g. 10, 20, 30, 40.
Then when I would like to move index 40 to be between 10 and 20 I first update the index to be 15 where index=40. And then update all the user's records once more restoring the 10, 20, 30, 40 order based on the select below.
select f.*,
@new_index:=@new_index+10 as new_index
from Favorites f, (select @new_index:=0) as sess_var
where f.user_id=:theUserId
order by f.index
The query will return you all the old records with new values for the index. Adapt it to be used in your second update.
UPDATE:
update Favorites f
join (the query above) sub on
f.user_id = sub.user_id and f.widget_id= sub.widget_id
set index=sub.new_index
Upvotes: 1