Making changes to multiple records based on change of single record with SQL

后端 未结 3 833
闹比i
闹比i 2020-11-28 00:17

I have a table of food items. They have a \"Position\" field that represents the order they should appear in on a list (listID is the list they are on, we don\'t want to re-

相关标签:
3条回答
  • 2020-11-28 00:34

    I do not think this can be conveniently done in less than two queries, which is OK, there should be as few queries as possible, but not at any cost. The two queries would be like (based on what you write yourself)

    UPDATE mytable SET position = 1 WHERE listID = 1 AND name = 'pears';
    UPDATE mytable SET position = position + 1 WHERE listID = 1 AND position BETWEEN 2 AND 4;
    
    0 讨论(0)
  • 2020-11-28 00:41

    This calls for a complex query that updates many records. But a small change to your data can change things so that it can be achieved with a simple query that modifies just one record.

    UPDATE my_table set position = position*10;
    

    In the old days, the BASIC programming language on many systems had line numbers, it encouraged spagetti code. Instead of functions many people wrote GOTO line_number. Real trouble arose if you numbered the lines sequentially and had to add or delete a few lines. How did people get around it? By increment lines by 10! That's what we are doing here.

    So you want pears to be the second item?

    UPDATE my_table set position = 15 WHERE listId=1 AND name = 'Pears'
    

    Worried that eventually gaps between the items will disappear after multiple reordering? No fear just do

    UPDATE my_table set position = position*10;
    

    From time to time.

    0 讨论(0)
  • 2020-11-28 00:44

    I've mostly figured out my problem. So I've decided to put an answer here incase anyone finds it helpful. I can make use of a CASE statement in SQL. Also by using Javascript beforehand to build my SQL query I can change multiple records.

    This builds my SQL query:

    var sql;
    var incrementDirection = (startPos > endPos)? 1 : -1;
    sql = "UPDATE mytable SET position = CASE WHEN position = "+startPos+" THEN "+endPos;
    for(var i=endPos; i!=startPos; i+=incrementDirection){
        sql += " WHEN position = "+i+" THEN "+(i+incrementDirection);
    }
    sql += " ELSE position END WHERE listID = "+listID;
    

    If I want to move Pears to before Chips. I can set:

    startPos = 4;
    endPos = 1;
    listID = 1;
    

    My code will produce an SQL statement that looks like:

    UPDATE mytable
    SET position = CASE
      WHEN position = 4 THEN 1
      WHEN position = 1 THEN 2
      WHEN position = 2 THEN 3
      WHEN position = 3 THEN 4
      ELSE position
    END
    WHERE listID = 1
    

    I run that code and my final table will look like:

    +--id--+--listID--+---name---+--position--+
    |   1  |     1    | cheese   |      0     |
    |   2  |     1    | chips    |      2     |
    |   3  |     1    | bacon    |      3     |
    |   4  |     1    | apples   |      4     |
    |   5  |     1    | pears    |      1     |
    |   6  |     1    | pie      |      5     |
    |   7  |     2    | carrots  |      0     |
    | 8,9+ |    3,4+  | ...      |     ...    |
    +------+----------+----------+------------+
    

    After that, all I have to do is run SELECT name FROM mytable WHERE listID = 1 ORDER BY position and the output will be as follows::

    cheese
    pears
    chips
    bacon
    apples
    pie
    
    0 讨论(0)
提交回复
热议问题