JeuWeb - Crée ton jeu par navigateur
[Solution MySQL] Classement avec égalité - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : [Solution MySQL] Classement avec égalité (/showthread.php?tid=6147)



[Solution MySQL] Classement avec égalité - srm - 21-05-2012

Bonjour,

Faire un classement sous MySQL est assez simple, un simple select avec un order et ça suffit.
Mais donner la position d'un joueur précis dans le classement (par exemple sur son compte ou sa fiche personnage) c'est déjà plus dur. Cependant on trouve des solutions sur internet assez facilement pour ce cas : https://jimlife.wordpress.com/2008/09/09/displaying-row-number-rownum-in-mysql/

Maintenant imaginons que vous avez ce classement :
1. Toto, 320 points
2. Tonton, 270 points
3. Tata, 270 points
4. Tutu, 220 points

Et que vous vouliez un classement qui gère les égalités et qui donne ça :
1. Toto, 320 points
2. Tonton, 270 points
2. Tata, 270 points
4. Tutu, 220 points

Encore une fois c'est assez simple à le faire avec n'importe quel langage quand on affiche toutes les lignes (encore que avec un classement sur plusieurs pages, ça devient un peu compliqué)

Mais de nouveau si vous voulez pouvoir afficher le classement d'un seul joueur, ça devient bien plus compliqué à faire.

Sous Oracle il existe des fonctions analytiques pour faire ça, pour le premier cas il s'agit de la fonction analytique row_number() et pour le second cas la fonction analytique rank(), je vais vous donner ici une solution pour pouvoir faire des classements de ce type, ça ne sera pas aussi puissant et souple que row_number() et rank() de Oracle, mais ça devrait suffire pour les besoins des jeux webs.

Alors voilà la requête qu'il faut utiliser :

select
@ROW_NUMBER:=@ROW_NUMBER+1 as rowNumber,
(case when @LAST_VALUE=points then @RANK:=@RANK else @RANK:=@ROW_NUMBER end) as rank,
(case when @LAST_VALUE<>points then @LAST_VALUE:=points end) as rankInternalProcess,
rankList.* from
(select * from scoreboard order by points desc) rankList,
(SELECT @LAST_VALUE:=0) lastValueInit,
(SELECT @ROW_NUMBER:=0) rowNumberInit,
(SELECT @RANK:=0) rankInit

Vous pouvez bien entendu remplacer la requête "select * from scoreboard order by points desc" par ce que vous voulez, mais si votre colonne sur laquelle se base le classement ne se nomme pas "points" vous devez changer dans le reste de la requête "points" par le nom de votre colonne.

Cette requête peut potentiellement être gourmande, je ne l'ai pas testé sur des gros classements de plusieurs centaines de millier de joueurs, j'ai eu la flemme de mettre en place un jeu de données pour effectuer ce test, si quelqu'un veut bien tester et me donner le EXPLAIN de sa requête avec et sans le système de classement, ça permettra à tout le monde de voir si cette requête peut poser problème.

Dans tous les cas, ça devrait rester moins gourmand que de faire l'équivalent en PHP/Ruby/etc...
Si vous avez d'autres solutions pour avoir ce type de classement, je vous écoute Smile


RE: [Solution MySQL] Classement avec égalité - Maks - 21-05-2012

J'ai rencontré aussi le problème. J'ai tout simplement créé une vue sous MySQL pour simplifier le truc et je cherche dans cette vue une position selon un critère... Bon après je suis pas une bête de SQL ^^


RE: [Solution MySQL] Classement avec égalité - srm - 21-05-2012

Et tu trouves comment la position ?
Tu gères les égalités ou tu parles d'un classement sans gestion des égalités ?


RE: [Solution MySQL] Classement avec égalité - Maks - 21-05-2012

Ma solution ne gère pas les égalités je pense en effet.

A chaque fois qu'un joueur consulte son "profil" ou le classement, je met à jour la vue :

CREATE OR REPLACE VIEW classement AS SELECT [...], puissance FROM joueurs ORDER BY puissance DESC

Puis lorsqu'il consulte son profil pour récupérer la position :


SELECT COUNT(puissance)+1 AS rang FROM classement WHERE puissance > {puissance_du_joueur}



RE: [Solution MySQL] Classement avec égalité - srm - 21-05-2012

Ça ne sert à rien de recréer la vue à chaque fois, ça n'est pas une vue matérialisée ce qui veut dire qu'à chaque fois que tu la consulte la requête qui la définis est exécuté.

En effet, tu ne gères pas les égalités, mais si tu en as pas besoin, c'est pas dérangeant Smile


RE: [Solution MySQL] Classement avec égalité - Maks - 21-05-2012

J'ai coupé le SELECT mais en fait je n'ai pas de champs puissance dans ma table, c'est une addition de champs existants (pv+energie+...), pour ça que je la met à jour à chaque fois Wink