Partage
  • Partager sur Facebook
  • Partager sur Twitter

Comparaison sur les ensembles

Sujet résolu
    20 décembre 2010 à 19:05:29

    Bonjour,
    J'ai une table de la forme:

    id élement
    1 salade
    1 pomme
    2 salade
    2 pomme
    2 orange


    cette table veut dire que j'ai deux ensembles:
    l'ensemble 1 qui contient une salade et une pomme
    l'ensemble 2 qui contient une salade, une pomme et une orange.

    Je souhaiterai trouver un moyen efficace (en pur SQL) pour avoir les id des ensembles qui contiennent exactement les mêmes éléments.

    Merci
    • Partager sur Facebook
    • Partager sur Twitter
      20 décembre 2010 à 22:13:13

      Je ne comprends pas ta question.
      • Partager sur Facebook
      • Partager sur Twitter
        20 décembre 2010 à 22:57:20

        Le chiffre de la première colonne est le n° du panier de fruits

        La seconde colonne liste les différents fruits dans les panier.

        Je veux retrouver les panier qui contiennent exactement les même fruits.
        • Partager sur Facebook
        • Partager sur Twitter
          20 décembre 2010 à 23:17:55

          Le seul truc que je vois, ce serait de créer une empreinte pour chaque panier, et regarde si une empreinte existe en plus d'un exemplaire. Par exemple, avec MySQL et GROUP_CONCAT :

          --
           SELECT GROUP_CONCAT(id_panier ORDER BY id_panier ASC)
             FROM (SELECT id_panier, GROUP_CONCAT(nom_fruit ORDER BY nom_fruit ASC) AS nom_fruits
                   FROM panier 
                   GROUP BY id_panier) tmp
          GROUP BY nom_fruits
            HAVING COUNT(*) > 1;
          


          Ce qui retournerait différentes listes de paniers identiques. Mais je trouve que ça fait moche avec autant de GROUP_CONCAT, je me demande s'il n'y a pas une solution plus élégante.
          • Partager sur Facebook
          • Partager sur Twitter
            21 décembre 2010 à 15:02:15

            C'est une bonne idée, dans la mesure ou les noms des fruits ne se recoupent pas.

            Un contre exemple serait:
            id élément
            1 pommefraise
            2 pomme
            2 fraise
            • Partager sur Facebook
            • Partager sur Twitter
              21 décembre 2010 à 16:52:20

              Euh, si tu construis ta table n'importe comment, c'est normal que ça fonctionne pas.
              • Partager sur Facebook
              • Partager sur Twitter
                21 décembre 2010 à 17:02:01

                Y a moyen :

                CREATE TABLE ensemble ( ens INTEGER NOT NULL, elem TEXT NOT NULL, PRIMARY KEY (ens,elem) );
                INSERT INTO ensemble VALUES 
                (1 , 'salade'),
                (1 , 'pomme'),
                (2 , 'salade'),
                (2 , 'pomme'),
                (2 , 'orange'),
                (3 , 'salade'),
                (3 , 'pomme'),
                (4 , 'salade');
                
                -- équivalent du GROUP_CONCAT (en mieux : pommefraise marche)
                SELECT array_agg( ens ), l FROM (
                  SELECT ens, array_agg( elem ) AS l FROM (
                    SELECT * FROM ensemble ORDER BY ens, elem 
                  ) AS e GROUP BY ens) 
                AS f GROUP BY l;
                
                 array_agg |           l           
                -----------+-----------------------
                 {2}       | {orange,pomme,salade}
                 {1,3}     | {pomme,salade}
                 {4}       | {salade}
                
                
                -- SQL pur, probablement beaucoup plus lent
                
                WITH 
                  tailles AS (SELECT ens, count(*) AS taille FROM ensemble GROUP BY ens),
                  candidats AS (SELECT a.ens aens, b.ens bens, a.taille FROM tailles a JOIN tailles b ON (a.taille=b.taille AND a.ens <= b.ens))
                  SELECT aens, bens, taille, count(*) AS identiques FROM candidats c JOIN ensemble a ON (a.ens=c.aens) JOIN ensemble b ON (b.ens=c.bens AND b.elem=a.elem) GROUP BY aens, bens, taille HAVING taille=count(*);
                
                 aens | bens | taille | identiques 
                ------+------+--------+------------
                    1 |    1 |      2 |          2
                    2 |    2 |      3 |          3
                    1 |    3 |      2 |          2
                    3 |    3 |      2 |          2
                    4 |    4 |      1 |          1
                


                Le dernier retourne des correspondances entre ensembles (par exemple aens=1 et bens=3 indique que les ensembles 1 et 3 sont identiques). C'est assez chiadé.

                CREATE TABLE ensemble ( ens INTEGER NOT NULL, elem INTEGER NOT NULL, PRIMARY KEY (ens,elem) );
                INSERT INTO ensemble (ens, elem) SELECT DISTINCT (n/10)::INTEGER, (random()*10)::INTEGER FROM generate_series( 1,10000 ) AS n;
                
                requête array_agg() : 0.012 s
                requête sql pur     : 1.02  s
                


                no comment sur les performances...

                > Euh, si tu construis ta table n'importe comment, c'est normal que ça fonctionne pas.

                Non, c'est GROUP_CONCAT qui est une aberration.
                • Partager sur Facebook
                • Partager sur Twitter
                  21 décembre 2010 à 17:07:41

                  Je voulais le faire avec array_agg au début, puis je me suis dit que de toute façon, il faudrait que je le refasse avec MySQL et GROUP_CONCAT parce que l'auteur ne comprendrait pas.

                  Par contre, j'ai pas compris comment ça marcherait si l'élément valait "pommefraise".
                  • Partager sur Facebook
                  • Partager sur Twitter
                    21 décembre 2010 à 17:15:47

                    Ben GROUP_CONCAT est un canon à pied parce que ça colle des strings dans une string, tu choisis le séparateur, par exemple "***", mais si une des chaînes d'origine contient le séparateur, c'est mort.

                    En l'occurence si y'a "pomme", "fraise" et "pommefraise" comme éléments de l'ensemble, après GROUP_CONCAT, tu sauras jamais si "pommefraise" était "pommefraise" ou "pomme" + "fraise", à moins de mettre un séparateur comme un espace, mais si il y a des espaces dans les chaînes d'origine, etc, etc.

                    Tandis qu'avec un array, au moins t'es sûr que les éléments sont des éléments...
                    • Partager sur Facebook
                    • Partager sur Twitter
                      21 décembre 2010 à 17:30:20

                      Oui, je comprends, mais si tu regardes comme ledemonboiteux conçoit sa base de données, il met dans le panier 1 l'élément "pommefraise" et dans le panier 2 les éléments "pomme" et "fraise", puis se demande pourquoi ça fonctionne pas...

                      Et par défaut, GROUP_CONCAT sépare les éléments par des virgules, donc dans les exemples montrés, ça devrait quand même fonctionner. Même si c'est certain qu'array_agg est une bien meilleure solution.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        10 janvier 2011 à 19:32:50

                        Fayden.
                        La méthode de Lord Casque Noir marche dans mon cas,
                        si j'ai un élément ``pommefraise'' il est bien distinct des éléments du tableau : pomme et fraise.

                        La confusion vient du fait que j'ai du mal expliquer mon exemple.
                        Si j'ai dans un même ensemble une pomme et une fraise, ma table d'origine aura:
                        1 pomme
                        1 fraise

                        Merci beaucoup pour vos réponses à tout les deux.
                        • Partager sur Facebook
                        • Partager sur Twitter

                        Comparaison sur les ensembles

                        × 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