1

I have a list of N ids (for example: 803, 518, 361) on a MySQL Server 5.7.24

Current values are

+-----+-------+
| id  | order |
+-----+-------+
| 361 |     1 |
| 518 |     2 |
| 803 |     3 |
+-----+-------+

I want to update order column from a list of ids, getting order from id position.

This query returns the correct rownum for each id:

SELECT `id`, (@rownumber := @rownumber + 1) `rownum`
FROM `comments`
CROSS JOIN (SELECT @rownumber := 0) `cross`
WHERE `id` IN (803, 518, 361)
ORDER BY FIELD (`id`, 803, 518, 361) ASC;

+-----+--------+
| id  | rownum |
+-----+--------+
| 803 |      1 |
| 518 |      2 |
| 361 |      3 |
+-----+--------+

But on update, this positions are not set:

UPDATE `comments` `target`
JOIN (
    SELECT `id`, (@rownumber := @rownumber + 1) `rownum`
    FROM `comments`
    CROSS JOIN (SELECT @rownumber := 0) `cross`
    WHERE `id` IN (803, 518, 361)
    ORDER BY FIELD (`id`, 803, 518, 361) ASC
) `source` ON `target`.`id` = `source`.`id`
SET `target`.`order` = `source`.`rownum`;

Query OK, 0 rows affected (0.00 sec)
Rows matched: 3  Changed: 0  Warnings: 0

The order value was not updated:

SELECT `id`, `order` FROM `comments`
WHERE `id` IN (361, 518, 803)
ORDER BY `order` ASC;

+-----+-------+
| id  | order |
+-----+-------+
| 361 |     1 |
| 518 |     2 |
| 803 |     3 |
+-----+-------+
3 rows in set (0.01 sec)

Where is the problem on the queries?

Thanks!

UPDATE 1:

Also, not working

UPDATE `comments` `target`, (
    SELECT `id`, (@rownumber := @rownumber + 1) `rownum`
    FROM `comments`
    CROSS JOIN (SELECT @rownumber := 0) `cross`
    WHERE `id` IN (803, 518, 361)
    ORDER BY FIELD (`id`, 803, 518, 361) ASC
) `source`
SET `target`.`order` = `source`.`rownum`
WHERE `target`.`id` = `source`.`id`;
Lito
  • 1,262
  • 2
  • 17
  • 25

3 Answers3

1

The following query should do the trick :

SET @rownumber = 0;
UPDATE comments
SET `order` = @rownumber:= @rownumber + 1
WHERE id IN (803, 518, 361)
ORDER BY id DESC;

See this db fiddle

GMB
  • 216,147
  • 25
  • 84
  • 135
1

Since id is the primary key, you could simply do:

UPDATE `comments`
       SET `order` = field(`id`,
                           803,
                           518,
                           316)
       WHERE `id` IN (803,
                      518,
                      361);

field() already produces the 1, 2 or 3.

sticky bit
  • 36,626
  • 12
  • 31
  • 42
0

As I'm working with queries on PHP, thanks to @GMB with idea about run two different statements:

$db->exec('SET @rownumber = 0;');

$db->exec('
    UPDATE `comments`
    SET `order` = @rownumber := @rownumber + 1
    WHERE `id` IN (803, 518, 361)
    ORDER BY FIELD (`id`, 803, 518, 361) ASC;
');
Lito
  • 1,262
  • 2
  • 17
  • 25