Partage
  • Partager sur Facebook
  • Partager sur Twitter

Requête SQL classement

en gérant les ex-aequo...

    19 octobre 2009 à 11:59:08

    Salut à tous,
    simplement pour pratiquer et m'améliorer un peu en SQL j'essaye de concevoir des requêtes pour différents problèmes...
    Je me suis donc penché sur le système de classement. Imaginons cette table :

    CREATE TABLE IF NOT EXISTS `classement` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `nom` varchar(20) NOT NULL,
      `points` int(11) NOT NULL DEFAULT '0',
      PRIMARY KEY (`id`)
    ) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
    
    INSERT INTO `classement` (`id`, `nom`, `points`) VALUES
    (1, 'albert', 3),
    (2, 'hubert', 5),
    (3, 'robert', 1),
    (4, 'alfred', 3);
    

    Pour faire une requête en récupérant le classement j'ai donc :
    set @rang = 0;
    select @rang:=@rang+1 rang,nom,points from classement order by points desc;
    

    Ce qui me donne :
    +------+--------+--------+
    | rang | nom    | points |
    +------+--------+--------+
    |    1 | hubert |      5 |
    |    2 | albert |      3 |
    |    3 | alfred |      3 |
    |    4 | robert |      1 |
    +------+--------+--------+

    Si je veux récupérer le rang d'un membre donné je fais donc :
    set @rang = 0;
    select rang,nom FROM (select id,@rang:=@rang+1 rang,nom,points from classement order by points desc) cl WHERE id=3;
    

    Cependant maintenant j'aimerais bien gérer les ex-aequo !
    J'aimerais donc avoir comme sortie pour ma première requête :
    +------+--------+--------+
    | rang | nom    | points |
    +------+--------+--------+
    |    1 | hubert |      5 |
    |    2 | albert |      3 |
    |    2 | alfred |      3 |
    |    4 | robert |      1 |
    +------+--------+--------+

    Cependant je bloque un peu... Je suis arrivé au résultat :
    +------+--------+--------+
    | rang | nom    | points |
    +------+--------+--------+
    |    1 | hubert |      5 |
    |    2 | albert |      3 |
    |    2 | alfred |      3 |
    |    3 | robert |      1 |
    +------+--------+--------+

    grâce aux requêtes :
    set @rang = 1;
    set @prec = (select max(points) from classement);
    select if(points<@prec,@rang:=@rang+1,@rang) rang,nom,points,@prec:=points prec from classement order by points desc;
    

    Mais il y a le problème du membre se situant apres plusieurs ex-aequo qui ne prends pas son vrai rang...

    Auriez vous une solution?

    merci à tous :)
    • Partager sur Facebook
    • Partager sur Twitter
      19 octobre 2009 à 14:06:50

      Salut ;) ,

      Si j'ai bien compris sa donne un truc comme sa :) :

      SET @rang = 1;
      SET @prec = (SELECT MAX(points) FROM classement);
      SELECT if( points < @prec , @rang := @rang+(SELECT COUNT(points) FROM classement WHERE points = @prec), @rang ) rang, nom, points, @prec := points AS prec FROM classement ORDER BY points DESC;
      

      Il suffit de compter le nombre de lignes qui ont la même valeur de points que la ligne précédente lorsqu'on rentre dans la condition. ( en comptant ce nombre de ligne on incrémente ainsi le rang en fonction du nombre d'ex-aequo précédent ).

      +------+--------+--------+
      | rang | nom    | points |
      +------+--------+--------+
      |    1 | hubert |      5 |
      |    2 | albert |      3 |
      |    2 | alfred |      3 |
      |    4 | robert |      1 |
      +------+--------+--------+

      • Partager sur Facebook
      • Partager sur Twitter
      - Activer les erreurs : PHP - PDO - MYSQLI - ¯\_ツ_/¯ - Documentations : PHP - MySQL -
        19 octobre 2009 à 14:25:23

        En fait, normalement la gestion des rangs se fait en PHP, c'est 100 fois plus pratique...
        SELECT nom,points FROM classement ORDER BY points DESC;
        Suffit donc de lire le résultat dans une boucle, ce que tu es obligé de faire et d'avoir une variable qui s'incrémente à chaque tour, rien de plus facile et c'est ce que je te conseille. Bien mieux qu'une manipulation MySQL (ceci dit savoir ce que tu sais en MySQL est toujours utile).

        NB: Les majuscules dans une requete SQL, les majuscules !
        • Partager sur Facebook
        • Partager sur Twitter
          19 octobre 2009 à 16:56:55

          Nice Sombrelune, thx.
          @IGstaff : Comme j'ai dit c'est pas du tout pour une application pratique mais surtout pour pratiquer un peu de SQL. Mais sinon ça me paraît quand même assez pratique pour sélectionner le rang d'un membre donné (membre courant par exemple). Après niveau perf je sais pas si c'est super...
          • Partager sur Facebook
          • Partager sur Twitter
            19 octobre 2009 à 18:39:58

            np :) , sinon ouais niveau performance c'est pas le must c'est sûr, vu la sous-requette qui est effectuée dans presque tout les cas sauf pour les suites de doublon dans la table, mais c'est pas la mort non plus, sa reste correct quand on l'utilise sur de petites tables, après c'est sûr si y'a 30.000 enregistrements dans la table sa risque de le faire moyen ^^ .

            Pour la question des majuscules c'est mieux de les mettre par convention, comme c'est le cas dans plusieurs autres SGBD, mais bon, MySQL restant assez souple sur l'analyse des requettes sa passera presque toujours, généralement c'est bien de les mettre pour MySQL pour pouvoir se repérer dans la requette sans la coloration syntaxique, c'est plus pratique ^^ .
            • Partager sur Facebook
            • Partager sur Twitter
            - Activer les erreurs : PHP - PDO - MYSQLI - ¯\_ツ_/¯ - Documentations : PHP - MySQL -

            Requête SQL classement

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown