Updating display order of multiple MySQL rows in one or very few queries

前端 未结 11 1231
迷失自我
迷失自我 2021-02-01 07:43

I have a table with say 20 rows each with a number for display order (1-20).

SELECT * FROM `mytable` ORDER BY `display_order` DESC;

From an adm

相关标签:
11条回答
  • 2021-02-01 07:57

    You should first ensure that the column has no UNIQUE index, otherwise mysql will tell you that the constraint is broken during the query. After that you can do things like:

    -- Move #10 down (i.e. swap #10 and #11)
    UPDATE mytable SET display_order =
      CASE display_order
        WHEN 10 THEN 11
        WHEN 11 THEN 10
      END CASE
    WHERE display_order BETWEEN 10 AND 11;
    
    -- Move #4 to #10
    UPDATE mytable SET display_order
      CASE display_order
        WHEN 4 THEN 10
        ELSE display_order - 1
      END CASE
    WHERE display_order BETWEEN 4 AND 10;
    

    But you should actually ensure that you do things in single steps. swapping in two steps will result in broken numbering if not using ids. i.e.:

    -- Swap in two steps will not work as demostrated here:
    
    UPDATE mytable SET display_order = 10 WHERE display_order = 11;
    -- Now you have two entries with display_order = 10
    
    UPDATE mytable SET display_order = 11 WHERE display_order = 10;
    -- Now you have two entries with display_order = 11 (both have been changed)
    

    And here is a reference to the CASE statement of mysql.

    0 讨论(0)
  • 2021-02-01 07:58

    Collect the new order in a temporary variable and put a "save this order" button to the admin area. Then save the order for the rows with one round.

    You'll get better response times, undoable changes, fewer modified rows (because in low level in the dbms, practically no updates used to be possible, but save a new instance of the whole row and delete the old one).

    After all, it would be a lower cost solution for a whole reordering and would save some coding on the update optimization.

    0 讨论(0)
  • 2021-02-01 08:00

    A little late, but it may be useful to someone else:

    UPDATE mytable SET display_order = FIND_IN_SET(rowId, '1,9,2,6,23') WHERE rowId in (1,9,2,6,23)
    
    0 讨论(0)
  • 2021-02-01 08:06

    You could delete an re-insert all the rows - that would do the whole operation in just two queries (or three if you need to select all the data). I wouldn't count on it being faster, and you'd have to do it inside a transaction or you'll be heading for your backups before too long. It could also lead to table fragmentation.

    A better option might be to record each change as a history then do something like this:

    Example, position 10 is moved down two to 12th

    UPDATE table SET display_order = display_order -1 WHERE display_order BETWEEN 10 AND 12
    UPDATE table SET display_order = 12 WHERE row_id = [id of what was row 10]
    
    0 讨论(0)
  • 2021-02-01 08:10

    I'm thinking about this problem, and the solution I came up is having a decimal number as order and change the number of the item change for a number between the next and the previous item

    Order    Item
    -----    ----
    1        Original Item 1
    2        Original Item 2
    3        Original Item 3
    4        Original Item 4
    5        Original Item 5
    

    If you change the item 4 to the 2nd position, you get:

    Order    Item
    -----    ----
    1        Original Item 1
    1.5      Original Item 4
    2        Original Item 2
    3        Original Item 3
    5        Original Item 5
    

    If you change the item 3 to the 3rd position, you get:

    Order    Item
    -----    ----
    1        Original Item 1
    1.5      Original Item 4
    1.75     Original Item 3
    2        Original Item 2
    5        Original Item 5
    

    Theoretically there is always a decimal between two decimals, but you could face some storage limits.

    This way you only have to update the row being re-ordered.

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