le tri d'une ORDER BY peut être enregistrée explicitement avec une seule instruction UPDATE?
Question
J'ai ce tableau:
SELECT * FROM items
id | item | position
---|-----------|----------
1 | USB cable | 0
2 | SD card | 4
3 | Mouse | 2
4 | Keyboard | 0
5 | Monitor | 3
Le tri ce tableau donne ce résultat:
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
Maintenant, je veux mettre à jour la table et enregistrer l'ordre dans la colonne de position:
SELECT * FROM items
id | item | position
---|-----------|----------
4 | Keyboard | 1
1 | USB cable | 2
3 | Mouse | 3
5 | Monitor | 4
2 | SD card | 5
Peut-on faire avec une seule requête ou dois-je faire une boucle manuellement sur toutes les lignes et une mise à jour manuelle faire?
Dans le cas où l'ordre n'est pas complètement défini (par exemple, pour au-dessus de câble USB et le clavier) Je viens arbitrairement décidé de l'ordre.
La solution
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
Note: l'ordre de « clavier » et « câble USB » est arbitraire. Ils ont tous deux position = 0
Pour tie-break positions basées sur l'article, ajoutez un tri secondaire
ROW_NUMBER() OVER (ORDER BY position, item) AS rn
Si vous avez la position en double, les paires d'articles, ce sera trop arbitraire ...
Autres conseils
Voici comment y parvenir dans 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;
J'ai utilisé vos données échantillon de la question, chargé dans MySQL 5.5.15 sur mon ordinateur portable, et a couru ces deux lignes. Voici le résultat:
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)