Может ли сортировка из оператора по заказу по оператору явно сохранена только с одним оператором обновления?
Вопрос
У меня есть эта таблица:
SELECT * FROM items
id | item | position
---|-----------|----------
1 | USB cable | 0
2 | SD card | 4
3 | Mouse | 2
4 | Keyboard | 0
5 | Monitor | 3
Сортировка этой таблицы дает этот результат:
SELECT * FROM items ORDER BY position
id | item | position
---|-----------|----------
4 | Keyboard | 0
1 | USB cable | 0
3 | Mouse | 2
5 | Monitor | 3
2 | SD card | 4
Теперь я хочу обновить таблицу и сохранить заказ в столбце позиции:
SELECT * FROM items
id | item | position
---|-----------|----------
4 | Keyboard | 1
1 | USB cable | 2
3 | Mouse | 3
5 | Monitor | 4
2 | SD card | 5
Можно ли это сделать с одним запросом или мне придется вручную зацикливаться на всех рядах и делать ручное обновление?
В случае, если заказ не полностью определен (например, для USB -кабеля и клавиатуры выше) я просто произвольно определил заказ.
Решение
UPDATE
T1
SET
position = T2.rn
FROM
myTable T1
JOIN
(
SELECT
id,
ROW_NUMBER() OVER (ORDER BY position) AS rn
FROM
myTable
) T2 ON T1.id = T2.id
Примечание. Порядок «клавиатуры» и «USB -кабеля» произвольный. У них обоих есть позиция = 0
Чтобы связать положения, на основе элемента, добавьте вторичное сортирование
ROW_NUMBER() OVER (ORDER BY position, item) AS rn
Если у вас есть дубликатная позиция, пары элементов это тоже будет произвольным ...
Другие советы
Вот как это добиться в MySQL:
set @x = 0;
update items A
inner join
(
select @x:=@x+1 newposition,id
from items
order by position
) B using (id)
set A.position=B.newposition;
Я использовал ваши образцы данных из вопроса, загрузил их в MySQL 5.5.15 на моем ноутбуке и запустил эти две линии. Вот результат:
mysql> use test
Database changed
mysql> drop table if exists items;
Query OK, 0 rows affected (0.01 sec)
mysql> create table items
-> (
-> id int not null auto_increment,
-> item varchar(20),
-> position int,
-> primary key(id)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert into items (item,position) values
-> ('USB cable',0),('SD Card',4),
-> ('Mouse',2),('Keyboard',0),('Monitor',3);
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select * from items;
+----+-----------+----------+
| id | item | position |
+----+-----------+----------+
| 1 | USB cable | 0 |
| 2 | SD Card | 4 |
| 3 | Mouse | 2 |
| 4 | Keyboard | 0 |
| 5 | Monitor | 3 |
+----+-----------+----------+
5 rows in set (0.00 sec)
mysql> select * from items order by position;
+----+-----------+----------+
| id | item | position |
+----+-----------+----------+
| 1 | USB cable | 0 |
| 4 | Keyboard | 0 |
| 3 | Mouse | 2 |
| 5 | Monitor | 3 |
| 2 | SD Card | 4 |
+----+-----------+----------+
5 rows in set (0.00 sec)
mysql> set @x = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> update items A
-> inner join
-> (
-> select @x:=@x+1 newposition,id
-> from items
-> order by position
-> ) B using (id)
-> set A.position=B.newposition;
Query OK, 5 rows affected (0.00 sec)
Rows matched: 5 Changed: 5 Warnings: 0
mysql> select * from items;
+----+-----------+----------+
| id | item | position |
+----+-----------+----------+
| 1 | USB cable | 1 |
| 2 | SD Card | 5 |
| 3 | Mouse | 3 |
| 4 | Keyboard | 2 |
| 5 | Monitor | 4 |
+----+-----------+----------+
5 rows in set (0.00 sec)
mysql> select * from items order by position;
+----+-----------+----------+
| id | item | position |
+----+-----------+----------+
| 1 | USB cable | 1 |
| 4 | Keyboard | 2 |
| 3 | Mouse | 3 |
| 5 | Monitor | 4 |
| 2 | SD Card | 5 |
+----+-----------+----------+
5 rows in set (0.00 sec)