简体   繁体   中英

What is the best approach to sort MySQL table rows by user choice?

Suppose we have a MySQL table (id , name) and a drag-and-drop-enabled list view of the table. User drags 90th row and places it over 10th row. What is the best approach to keep this new sorting?

  • I do not mean to keep sorting for every use separately
  • The HTML/JavaScript is not the problem

I have seen some programmers add a weight column to table, setting lower number upper in the table. In my example it will be 1 to 100. The problem is in case of above example (90 to 10) updating 81 rows is required. 90 changes to 10 and each 10 to 89 increments. Is it efficient in MySQL? Is there any better solution?
Another way maybe is saving new order as a string in another table, but in this case we lose MySQL sorting in retrieval phase!

I remember when we learned trie tree structure in university as an indexing tool, we said wow! Even when we took advantage of every single bit of a byte, 1.5 GB of pure text data stored in less than 500KB!!! So right now I still search to find a better answer!

Even programming languages when updating indexes for an array that had an object added in a previously occupied index adds one to each index.

You're going to have to end up updating the index for every single row.

The cleanest way to do that however would be something like this (where people is a non trivial table of course):

UPDATE people
SET index = index + 1
WHERE index BETWEEN $newIndex AND $oldIndex;

depending on your database, between might include or exclude the high and low bound numbers. Just make sure you know how it treats them!

Rather than adding a weight column to the MYSQL table, add a next_object column to the table.

It would function kind of like a linked list (if you're familiar with that). Every object entered will point to the next object.

Let's go through the scenario of moving a position 90 object to position 10.

First, you need to update the 89th object so that it now points to the 91st object (the new 90th object)

Then, you need to update the 9th object, and have it point to the 90th object (the new 10th object)

Last, you need to update the 90th object (the new 10th object), and have it point to the 10th object (the new 11th object)

And of course by point I mean, update the next_object field to the object I say I'm pointing to.

What exactly could you put as a value in the next_object field though? Just the object's ID, or something similar.

I just came up with this system as an alternative when I started writing this answer, so I'm not sure it's the most effective way. But hey, updating 3 objects is better than a potential 100,000 (if you had 100,000 objects).

At last, I made the sort by this method: I created a weight column. Each row after insertion gets its id as weight value. It ensures that new row will be at end. weight column is type of FLOAT. Jquery helps to get new position of the row, plus prev() and next() table row. Right new we have three situations that are commented in the fallowing snippet (After retriving IDs from rows and sending Ajax to PHP):

    #table of DB
    $table = $_POST['table'];
    #the id of the row on top
    $t = $_POST['t'];
    #the id of the row on middle
    $m = $_POST['m'];
    #the id of the row on bottom
    $b = $_POST['b'];
    switch ('') {
        #top is empty, so the row is droped on top
        case $t:
            #we set middle weigh 0.5 lower than its bottom
            $query = "
                UPDATE `$table` m, `$table` b
                SET m.`weight` = b.`weight`-0.5
                WHERE m.`id` = $m
                AND b.`id` = $b
            ";
            break;
        #bottom is empty, so the row is droped on the end
        case $b:
            #we set middle weigh 0.5 upper than its top
            $query = "
                UPDATE `$table` m, `$table` t
                SET m.`weight` = t.`weight`+0.5
                WHERE m.`id` = $m
                AND t.`id` = $t
            ";
            break;
        #values are not empty, so the row is droped in the middle part
        default:
            #we set middle weigh exactly between top and bottom
            $query = "
                UPDATE `$table` m, `$table` t, `$table` b
                SET m.`weight` = (t.`weight`+b.`weight`)/2
                WHERE m.`id` = $m
                AND t.`id` = $t
                AND b.`id` = $b
            ";
            break;
    }
    Yii::app()->db->createCommand($query)->query();

Even after 45 times of dividing 1 to 2, float value will not drop to zero, so I this solution is a remedy right now!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM