Partage
  • Partager sur Facebook
  • Partager sur Twitter

Selectionner valeu max d'une colonne par rapport à une autre

en une requête (sous requête)

    6 janvier 2011 à 15:43:37

    Bonjour,

    J’ai le problème suivant, j'ai deux champs d'entiers (ID1 et ID2) et je souhaiterais récupérer la valeur max de ID2 pour chaque ID1.
    Contrainte : ID1 contient des entiers qui se répètent.

    Exemple de ma_table :

    ID1 / ID2
    1 / 12
    1 / 14
    1 / 52
    8 / 55
    5 / 32
    2 / 33
    2 / 35
    5 / 301
    5 / 309

    Je souhaiterais donc récupérer le plus grand ID2 de chaque ID1 (par exemple ici ID2=52 pour ID1=1, ID2=35 pour ID1=2, ID2=309 pour ID1 =5 et ID2=55 pour ID1=8).

    Est-il possible de faire cela sans passer par 2 requêtes ? Si oui comment structurer la sous-requête ?
    J’ai pensé à passer par deux SELECT DISTINCT ID1 FROM ma_table et SELECT MAX(ID2) FROM ma_table puis combiner les valeur reçu d'une requête pour m'en servir dans l'autre.
    Mais je trouve que ça ne fait pas très propre

    Je vous remercie pour votre aide
    • Partager sur Facebook
    • Partager sur Twitter
      6 janvier 2011 à 15:59:30

      select max(id2) from latable group by id1
      
      et GG ^^
      • Partager sur Facebook
      • Partager sur Twitter
        7 janvier 2011 à 10:08:27

        Bonjour, je te remercie Angelo...

        Mais en faite chez moi ca prend le plus petit id2 pour chaque id1 :(
        Je crois que ca prend le premier id1 (dont le id2 est le plus petit) et laisse les autres id1 de coté
        • Partager sur Facebook
        • Partager sur Twitter
          7 janvier 2011 à 10:37:14

          Etrange surtout que je viens de testé et ça fonctionne bien :

          CREATE TABLE IF NOT EXISTS `table1` (
            `id1` int(11) NOT NULL,
            `id2` int(11) NOT NULL
          ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
          
          
          INSERT INTO `table1` (`id1`, `id2`) VALUES
          (1, 12),
          (1, 14),
          (1, 52),
          (8, 55),
          (5, 32),
          (2, 33),
          (2, 35),
          (5, 301),
          (5, 309);
          


          SELECT id1, max( id2 )
          FROM table1
          GROUP BY id1
          LIMIT 0 , 30
          


          id1    max(id2)
          1         52
          2         35
          5         309
          8         55
          • Partager sur Facebook
          • Partager sur Twitter
            7 janvier 2011 à 12:29:31

            tu peux nous donner le résultat de

            SHOW CREATE TABLE ma_table;
            


            Juste pour vérifier que les types / collations sont OK ? :p
            • Partager sur Facebook
            • Partager sur Twitter
              8 janvier 2011 à 15:56:45

              Bonjour, pour commencer j'ai résolu mon problème et je vais vous expliquer comment je m'y suis pris.
              La méthode d'Angelo ne marche malheureusement pas pour mon cas car n'étant pas rentré dans les détails de mon problème, dans la requête :
              select max(id2) from latable group by id1
              


              Je dois en faite retourner plusieurs valeurs comme ceci :

              select max(id2), champX, champX from latable where bidule='parametre' group by id1
              


              Sauf que... ça ne marche pas

              Donc je fais :
              TANT QUE select distinct id1 from latable where bidule='parametre' /*tout les id1 où il y a bidule égal au paramètre*/
                       TANT QUE select max(id2) from latable where id1='id1' /*on selectionne tout les id2 les plus élevés où les lignes id1 ont bidule = 'parametre' */
                                select champX, champY from latable where id1='id1' and id2='id2' /*et le tour est joué !!!*/
                       FIN TANT QUE
              FIN TANT QUE
              



              Alors histoire que cet algorithme serve à quelqu'un, il s'agit de donner un nom unique à une chaine de caractères :
              ex : SalutCaVa1.0 SalutCaVa1.1 SalutCaVa1.x etc
              avec SalutCaVa id1 . id2

              Voila, un grand merci à Angelo tout de même pour m'avoir aidé à mieux comprendre le group by (que je n'utilisais pas avant...)

              PS: si vous connaissez un algo plus court ce serait gentil ! ^^

              Merci

              EDIT : commentaire mal écrit dans le code
              • Partager sur Facebook
              • Partager sur Twitter
                8 janvier 2011 à 18:51:05

                On écrit pas un algorithme quand on a besoin d'une requête, on écrit une requête. Là, j'ai l'impression que tu es en train de faire une requête dans une boucle imbriquée... deux fois plutôt qu'une. C'est la pire solution et la chose à ne jamais faire.

                Lorsque tu as un problème, décris-le toujours précisément avec les vraies variables. C'est complètement inutile de nous donner un exemple semblable, dans la majorité des cas il y a toujours une contrainte qui a été oubliée. C'est une perte de temps autant pour toi que pour les gens qui essaient de t'aider.

                Bref, tu sembles vouloir une requête dans ce genre :

                SELECT colX, colY
                FROM ta_table
                INNER JOIN (SELECT id1, MAX(id2) AS id2
                            FROM ta_table
                            GROUP BY id1) tmp
                        USING (id1, id2)
                


                Mais comme on a ni structure des tables, ni jeu d'essai, ni énoncé précis, c'est difficile de faire quelque chose de correct.
                • Partager sur Facebook
                • Partager sur Twitter
                  8 janvier 2011 à 20:01:56

                  Bonsoir Fayden,

                  Je cherchais justement une sous-requête dans ce genre, parce qu'actuellement je suis obligé de passer par 3 requêtes pour arriver à ce que je souhaite.

                  Mais il y a une chose que je n'ai pas compris, n'ayant jamais utilisé de USING, je ne comprend pas ce que signifie le : tmp juste avant.

                  Que signifie tmp ? Est ce une nouvelle table ? Parce que pour mon cas, tout se joue sur les colonnes d'une seule et même table.


                  Merci
                  • Partager sur Facebook
                  • Partager sur Twitter
                    8 janvier 2011 à 20:07:21

                    C'est une jointure. En gros, si tu connais INNER JOIN ... ON ..., c'est pratiquement identique. La seule différence, c'est que USING regroupe les colonnes identiques.

                    Pour tmp, c'est un alias. Lorsqu'on utilise une sous-requête comme table, il faut nécessairement lui donner un alias, mais si on ne s'en sert pas. Dans ce cas-ci, c'est inutile, mais si j'avais utilisé la syntaxe avec ON, j'aurais dû écrire quelque chose comme -- ... ON ta_table.id1 = tmp.id1 AND ta_table.id2 = tmp.id2
                    • Partager sur Facebook
                    • Partager sur Twitter
                      16 janvier 2011 à 12:49:08

                      Bonjour Fayden, cette sous-requête fonctionne très avec USING ou ON.

                      Ainsi dans la table ta_table je peux récupérer tout les plus grands id2 de chaque id1 et y relever les paramètres colX et colY avec :

                      Avec USING :
                      SELECT colX, colY FROM ta_table INNER JOIN (SELECT id1, MAX(id2) AS id2 FROM ta_table GROUP BY id1) tmp USING (id1, id2)
                      

                      Ou bien avec ON :
                      SELECT colX, colY FROM ta_table INNER JOIN (SELECT id1, MAX(id2) AS id2 FROM ta_table GROUP BY id1) tmp ON ta_table.id1 = tmp.id1 AND ta_table.id2 = tmp.id2
                      



                      La touche finale que je souhaiterais y apporter, c'est d'ajouter une condition avec WHERE pour utiliser un filtre supplémentaire (de deux champs cond1 et cond2 appartenant aussi à ta_table), malheureusement, cela ne fonctionne pas :

                      SELECT colX, colY FROM ta_table INNER JOIN (SELECT id1, MAX(id2) AS id2 FROM ta_table WHERE (ta_table.cond1='$cond1') AND (ta_table.cond2='$cond2') GROUP BY id1) tmp ON ta_table.id1 = tmp.id1 AND ta_table.id2 = tmp.id2
                      


                      SELECT colX, colY FROM ta_table INNER JOIN (SELECT id1, MAX(id2) AS id2 FROM ta_table GROUP BY id1) tmp ON ta_table.id1 = tmp.id1 AND ta_table.id2 = tmp.id2 WHERE (ta_table.cond1='$cond1') AND (ta_table.cond2='$cond2')
                      


                      SELECT colX, colY FROM ta_table INNER JOIN (SELECT id1, MAX(id2) AS id2 FROM ta_table WHERE (ta_table.cond1='$cond1') AND (ta_table.cond2='$cond2') GROUP BY id1) tmp ON ta_table.id1 = tmp.id1 AND ta_table.id2 = tmp.id2 WHERE (ta_table.cond1='$cond1') AND (ta_table.cond2='$cond2')
                      


                      PS: J'ai choisis l'exemple avec ON parce que je suis habitué aux INNER JOIN...

                      Où peut-on placer le WHERE dans la structure de ce type de requête ?

                      Je vous remercie.

                      • Partager sur Facebook
                      • Partager sur Twitter

                      Selectionner valeu max d'une colonne par rapport à une autre

                      × 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