Reordering of column data in mysql

后端 未结 4 1435
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-07 11:47

I have a table like so:

categoryID      categoryName
----------------------------
     1            A
     2            B
     3            C
相关标签:
4条回答
  • 2021-01-07 12:29

    You could keep order as integer and renumber all the items between a drag's source index and destination index because they can't drag that far, especially as only 20 odd categories. Mulit-item drags make this more complicated however.

    Float is easier, but each time they move you find the middle you could very quickly run out of precission, I would write a test for this to check it doesn't finally give up working if you keep moving the 3rd item to the 2nd pos over and over.

    Example:

    1,2,3
    Move 3rd to 2nd
    1,1.5,2
    Move 3rd to 2nd
    1,1.25,1.5
    Move 3rd to 2nd
    1,1.125,1.25
    

    Do that in an excel spread sheet and you'll find the number becomes too small for floats to deal with in about 30 iterations.

    0 讨论(0)
  • 2021-01-07 12:39

    If the number of changes is rather small you can generate a clumsy but rather efficient UPDATE statement if the you know the ids of the involved items:

    UPDATE categories
    JOIN (
        SELECT 2 as categoryID, 3 as new_order
        UNION ALL
        SELECT 3 as categoryID, 4 as new_order
        UNION ALL
        SELECT 4 as categoryID, 2 as new_order) orders
    USING (categoryId)
    SET `order` = new_order;
    

    or (which I like less):

    UPDATE categories
    SET `order` = ELT (FIND_IN_SET (categoryID, '2,3,4'),
                       3, 4, 2)
    WHERE categoryID in (2,3,4);
    

    UPD:

    Assuming that you know the current id of the category (or its name), its old position, and its new position you can use the following query for moving a category down the list (for moving up you will have to change the between condition and new_rank computation to rank+1):

    SET @id:=2, @cur_rank:=2, @new_rank:=4;
    
    UPDATE t1
    JOIN (
      SELECT categoryID, (rank - 1) as new_rank
      FROM t1
      WHERE rank between @cur_rank + 1 AND @new_rank
      UNION ALL
      SELECT @id as categoryID, @new_rank as new_rank
    ) as r
    USING (categoryID)
    SET rank = new_rank;
    
    0 讨论(0)
  • 2021-01-07 12:42

    The idea with Float sounds reasanoble, just don't show these numbers to a user -)

    Whenever user moves an entry up or down, you can figure out entries above and below. Just take their Order number and find mean value - that is a new order for the entry that has been moved.

    0 讨论(0)
  • 2021-01-07 12:46

    Ok, here's the same that @newtover suggests, but these 2 simple queries can be much easier understood by any other developer, even unexperienced.

    Let's say we have a table t1:

    id      name    position
    -------------------------------------
     1      A       1
     2      B       2
     3      C       3
     4      D       4
     5     -E-      5
     6      F       6
    

    Let's move item 'E' with id=5 to 2nd position:

    1) Increase positions for all items between the old position of item 'E' and the desired position of 'E' (positions 2, 3, 4)

    UPDATE t1 SET position=position+1 WHERE position BETWEEN 2 AND 4
    

    2) Now there is no item at position 2, so 'E' can take it's place

    UPDATE t1 SET position=2 WHERE id=5
    

    Results, ordered by 'position'

    id      name    position
    -------------------------------------
     1      A       1
     5     -E-      2
     2      B       3
     3      C       4
     4      D       5
     6      F       6
    

    Just 2 simple queries, no subqueries.

    Restriction: column 'position' cannot be UNIQUE. But perhaps with some modifications it should work as well.

    Haven't tested this on large datasets.

    0 讨论(0)
提交回复
热议问题