Une option consiste à utiliser une variable de classement, telle que la suivante :
UPDATE player
JOIN (SELECT p.playerID,
@curRank := @curRank + 1 AS rank
FROM player p
JOIN (SELECT @curRank := 0) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
Le JOIN (SELECT @curRank := 0)
part permet l'initialisation de la variable sans nécessiter un SET
séparé commande.
Pour en savoir plus sur ce sujet :
- SQL :Classement sans auto-jointure
- Débordement de pile :Créer une colonne de somme cumulée dans MySQL
Scénario de test :
CREATE TABLE player (
playerID int,
points int,
rank int
);
INSERT INTO player VALUES (1, 150, NULL);
INSERT INTO player VALUES (2, 100, NULL);
INSERT INTO player VALUES (3, 250, NULL);
INSERT INTO player VALUES (4, 200, NULL);
INSERT INTO player VALUES (5, 175, NULL);
UPDATE player
JOIN (SELECT p.playerID,
@curRank := @curRank + 1 AS rank
FROM player p
JOIN (SELECT @curRank := 0) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
Résultat :
SELECT * FROM player ORDER BY rank;
+----------+--------+------+
| playerID | points | rank |
+----------+--------+------+
| 3 | 250 | 1 |
| 4 | 200 | 2 |
| 5 | 175 | 3 |
| 1 | 150 | 4 |
| 2 | 100 | 5 |
+----------+--------+------+
5 rows in set (0.00 sec)
MISE À JOUR : Je viens de remarquer que vous avez besoin d'égalité pour partager le même rang. C'est un peu délicat, mais peut être résolu avec encore plus de variables :
UPDATE player
JOIN (SELECT p.playerID,
IF(@lastPoint <> p.points,
@curRank := @curRank + 1,
@curRank) AS rank,
@lastPoint := p.points
FROM player p
JOIN (SELECT @curRank := 0, @lastPoint := 0) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
Pour un cas de test, ajoutons un autre joueur avec 175 points :
INSERT INTO player VALUES (6, 175, NULL);
Résultat :
SELECT * FROM player ORDER BY rank;
+----------+--------+------+
| playerID | points | rank |
+----------+--------+------+
| 3 | 250 | 1 |
| 4 | 200 | 2 |
| 5 | 175 | 3 |
| 6 | 175 | 3 |
| 1 | 150 | 4 |
| 2 | 100 | 5 |
+----------+--------+------+
6 rows in set (0.00 sec)
Et si vous avez besoin du rang pour sauter une place en cas d'égalité, vous pouvez ajouter un autre IF
condition :
UPDATE player
JOIN (SELECT p.playerID,
IF(@lastPoint <> p.points,
@curRank := @curRank + 1,
@curRank) AS rank,
IF(@lastPoint = p.points,
@curRank := @curRank + 1,
@curRank),
@lastPoint := p.points
FROM player p
JOIN (SELECT @curRank := 0, @lastPoint := 0) r
ORDER BY p.points DESC
) ranks ON (ranks.playerID = player.playerID)
SET player.rank = ranks.rank;
Résultat :
SELECT * FROM player ORDER BY rank;
+----------+--------+------+
| playerID | points | rank |
+----------+--------+------+
| 3 | 250 | 1 |
| 4 | 200 | 2 |
| 5 | 175 | 3 |
| 6 | 175 | 3 |
| 1 | 150 | 5 |
| 2 | 100 | 6 |
+----------+--------+------+
6 rows in set (0.00 sec)
Remarque :Veuillez considérer que les requêtes que je suggère pourraient être simplifiées davantage.