Forum Programmation.SQL mysql: selectioner une partie des données

Posté par  .
Étiquettes : aucune
0
18
juin
2007
Bonjour,

j'aurais besoin de conseils pour faire la somme d'une petit partie seulement des notes.

ma table est composée comme cela:


+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| id | double unsigned | | PRI | NULL | auto_increment |
| nom | varchar(50) | YES | | NULL | |
| prenom | varchar(50) | YES | | NULL | |
| cat | varchar(50) | YES | | NULL | |
| equipe | int(10) unsigned | | | 1 | |
| note | decimal(3,2) | YES | | NULL | |
+-------------+------------------+------+-----+---------+----------------+


j'ai donc plusieurs notes ( 5 ) par équipe ( ~20 ).

j'ordre les notes par équipe:


SELECT equipe,note FROM table ORDER BY equipe,note DESC;
+--------+----------+
| equipe | note |
+--------+----------+
| 1 | 22.00 |
| 1 | 21.00 |
| 1 | 12.00 |
| 1 | 11.00 |
| 1 | 3.00 |
| 2 | 10.00 |
| 2 | 6.00 |
| 2 | 6.00 |
| 2 | 5.00 |
| 2 | 4.00 |
| 3 | 10.00 |
| 3 | 9.00 |
| 3 | 8.00 |
| 3 | 5.00 |
| 3 | 8.00 |
|... |... |
+--------+----------+


je calcule la somme de toutes les notes puis les ordres:


SELECT DISTINCT equipe,sum(note) AS total FROM table GROUP BY equipe ORDER BY total DESC;
+--------+-------+
| equipe | total |
+--------+-------+
| 1 | 69.00 |
| 3 | 40.00 |
| 2 | 31.00 |
|... | |
+--------+-------+


mais je ne trouve pas le moyen de selectioner que les 3 plus gros note (par équipe) pour la sum(),
soit 55 pour l'équipe 1, 22 pour la 2 etc..


la fonction "limit 3" me coup le resultat et faudrait alors repéter l'opération pour chaque équipe (WHERE equipe=1)( une solution qui ne me plait pas beaucoup). et paraille avec une numérotation des lignes:


SET @n=0;
SELECT equipe,note,@n:=@n+1 ...



Je suis donc preneur de tous vos avis.

Merci d'avance.
  • # DISTINCT.

    Posté par  . Évalué à 4.

    désolé, c'est pas pour te donner la solution, mais pour te signaler que ton DISTINCT ne sert a rien, mais alors a rien du tout puisque tu fais un GROUP BY dessus...

    SELECT DISTINCT equipe,sum(note) AS total FROM table GROUP BY equipe ORDER BY total DESC;


    a changer en :

    SELECT equipe,sum(note) AS total FROM table GROUP BY equipe ORDER BY total DESC;
    • [^] # Re: DISTINCT.

      Posté par  . Évalué à 1.

      merci pour la remarque. j'ai consctruit ma requet part étape, et avant que je met un "sum" qui demande un "group by" j'en avais besion. je vais corrigé
  • # Solution détournée...

    Posté par  . Évalué à 2.

    Hello,
    je ne vois pas comment procéder autrement que passer par un script et une table temporaire.
    Le script devrait ressembler à ça :
    1) tu boucles pour chaque équipe trouvée,
    2) tu fais un select into temp x equipe, note from table order by note desc limit 3;
    3) tu appliques ta requête finale à la table temporaire :
    select equipe, sum(note) from x;

    Voilà, c'est un peu capilloctracté, mais au moins, ça fonctionne.
    • [^] # Re: Solution détournée...

      Posté par  . Évalué à 2.

      ARgg...
      Une petite précision quand même... Pour le point 2, il faut bien sûr limiter les résultats par équipe trouvée en 1).
      Donc, en code php, ça donnerait quelque chose comme ça :

      <?php
      $req1 = "select distinct equipe from table;";
      $resId1 = mysql_query ($connId, $req1); $index1 = 0;
      while ($rSet1 = mysql_fetch_row ($resId1, $index1++))
      {
      $req2 = "select into temp x equipe, note from table where equipe = {$rSet1[0]} order by note desc limit 3;";
      mysql_query ($connId, $req2);
      }
      $reqFin = "select equipe, sum(note) from x order by equipe;";
      /// Exécution et affichage des résultats.
      ?>

      Voilà, en espérant que ça aide.
      • [^] # Re: Solution détournée...

        Posté par  . Évalué à 1.

        j'ai trouvé un truc un peut barbare qui me selectione les x valeurs voulu par equipe:
        set @n=0,@eq=0;
        select if( if(@eq=equipe,@n:=@n+1,@n:=0)<'2',note,0) as selection,@eq:=equipe 
        from concours order by equipe,note desc;
        +-----------+-------------+
        | selection | @eq:=equipe |
        +-----------+-------------+
        |     22.00 |           1 |
        |     21.00 |           1 |
        |         0 |           1 |
        |         0 |           1 |
        |         0 |           1 |
        |     10.00 |           2 |
        |      6.00 |           2 |
        |         0 |           2 |
        |         0 |           2 |
        |     10.00 |           3 |
        |      9.00 |           3 |
        |         0 |           3 |
        |         0 |           3 |
        |      6.00 |           4 |
        |      0.00 |           4 |
        +-----------+-------------+
        
        
        mais la somme me pose encore problème. et je pense que niveau performance ça dois pas être jolie. je vais donc me pencher sur votre solution qui me parrait bien adapté, mais pour faire simple j'avais mis qu'une note par personne, je devrais en avoir plus de 6 par personne... merci Gyro Gearllose.
        • [^] # Re: Solution détournée...

          Posté par  . Évalué à 2.

          Pas de quoi...
          Je me suis encore mal relu, et j'ai oublié le group by dans la dernière requête. M'enfin, ce qui compte, c'est que l'idée soit là.
          Il va sans dire que ce script peut-être rédigé dans n'importe quel langage, car il n'y a pas que le php, mais c'est le seul que je maîtrise suffisement.
          Si c'est pour une question de performance, il devrait être possible aussi de rédiger une procédure stockée qui fasse le même boulot, mais là, ça dépasse mes connaissances de mysql.
          Enfin, juste pour information, la table temporaire ne sera utilisable que pendant la durée de vie de la connexion qui la créée. Donc, fin de script, fin de la table temporaire.
          Voilà pour ces quelques précisions de dernière minute.
          • [^] # Re: Solution détournée...

            Posté par  . Évalué à 2.

            une idée...

            avec une view (create view) je pense qu'on peut le faire.

            dans la vue, on fait la requete qui ne selectionne que les 3 plus grosses notes (limit).
            et dans la requete, on utilise la vue (à la place de le table donc) et on y fais la somme...
            • [^] # Re: Solution détournée...

              Posté par  . Évalué à 1.

              la fonction view est integre depuis la version 5 ( que j'ai pas encore) mais en m'inspirant fortement de l'exemple de Gyro Gearllose voila une solution: ( la fonction mysdl_fetch_row accept une seul parametre dans ma version)
              	$req1 = "CREATE TEMPORARY TABLE tmp (equipe decimal(3,2), note decimal(3,2))";
              	$res1 = mysql_query ($req1);
              
              	$req2 = "SELECT DISTINCT equipe FROM $dbtable";
              	$res2 = mysql_query($req2);
              
              	while(list($rSet1)=mysql_fetch_array($res2))
              	{
              		$req3 = "INSERT INTO tmp SELECT equipe,note*maj FROM $dbtable WHERE equipe={$rSet1[0]} ORDER BY sol_note DESC LIMIT 3";
              		$res3 = mysql_query ($req3);
              
              	}
              		
              	$req4 = "SELECT equipe,SUM(note) AS s FROM tmp GROUP BY equipe ORDER BY s DESC";
              	$res4 = mysql_query ($req4);
              
              voila mission accomplie , merci a vous

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.