Последовательное обновление таблицы MySQL - PullRequest
0 голосов
/ 12 июня 2018

Учитывая приведенную ниже таблицу, как я могу последовательно изменить порядок position от 1 до N, используя один запрос после удаления одной или нескольких строк и сохраняя при этом порядок position?

+---------+----------+-----+
| id (pk) | position | fk  |
+---------+----------+-----+
|       4 |        1 | 123 |
|       2 |        2 | 123 |
|      18 |        3 | 123 |
|       5 |        4 | 123 |
|       3 |        5 | 123 |
+---------+----------+-----+

Например, если position = 1 (id = 4) было удалено, желаемыми окончательными записями будут:

+---------+----------+-----+
| id (pk) | position | fk  |
+---------+----------+-----+
|       2 |        1 | 123 |
|      18 |        2 | 123 |
|       5 |        3 | 123 |
|       3 |        4 | 123 |
+---------+----------+-----+

и если position = 3 (id = 18) былоудалены, желаемые окончательные записи:

+---------+----------+-----+
| id (pk) | position | fk  |
+---------+----------+-----+
|       4 |        1 | 123 |
|       2 |        2 | 123 |
|       5 |        3 | 123 |
|       3 |        4 | 123 |
+---------+----------+-----+

Я могу сделать что-то вроде следующего, если была удалена только строка, но не для нескольких строк.

DELETE FROM mytable WHERE fk=123 AND position = 4;
UPDATE mytable SET position=position-1 WHERE fk=123 AND position > 4;

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

Вы можете использовать обновление и функцию ROW_NUMBER () .Если вы заказываете по позиции, то все должно быть в порядке.

UPDATE [1]
SET POSITION = [2].RN
FROM t [1]
JOIN (
       SELECT 
           t.ID
           , ROW_NUMBER() OVER (ORDER BY POSITION DESC) AS RN
       FROM t
     ) [2] 
ON [1].id = [2].id

Как уже упоминалось, это не относится к MySql.Извините за неверную информацию, так как я не увидел метку.

0 голосов
/ 12 июня 2018

Пользовательские переменные на помощь, если вы еще не используете MySQL 8, который предоставляет оконные функции, такие как ROW_NUMBER ():

UPDATE t
JOIN (

    SELECT 
    t.*
    , @n := @n + 1 as n
    FROM t
    , (SELECT @n := 0) var_init
    ORDER BY position

) sq ON t.id = sq.id
SET t.position = sq.n;
  • посмотрите, как это работаетжить в sqlfiddle

БОНУС:

Это становится немного сложнее, когда у вас несколько групп.
Например,для примеров данных, подобных этому

|  id | position |  fk |
|-----|----------|-----|
|   4 |        1 | 123 |
|   2 |        2 | 123 |
|   5 |        4 | 123 |
|   3 |        5 | 123 |
|  40 |        1 | 234 |
|  20 |        2 | 234 |
| 180 |        3 | 234 |
|  30 |        5 | 234 |

, запрос будет

UPDATE t
JOIN (

    SELECT 
    t.*
    , @n := if(@prev_fk != fk, 1, @n + 1) as n
    , @prev_fk := fk
    FROM t
    , (SELECT @n := 0, @prev_fk := NULL) var_init
    ORDER BY fk, position

) sq ON t.id = sq.id
SET t.position = sq.n;

Здесь вы просто сохраните текущий fk в другой переменной.При обработке следующей строки переменная по-прежнему содержит значение «предыдущей строки».Затем вы сбрасываете переменную @n, когда значение изменяется.

  • видит, как оно работает в реальном времени в sqlfiddle

UPDATE:

В MySQL 8 вы можете использовать оконную функцию row_number() следующим образом:

update t join (
    select t.*, row_number() over (partition by fk order by position) as new_pos 
    from t
) sq using (id) set t.position = sq.new_pos;
...