Partage
  • Partager sur Facebook
  • Partager sur Twitter

Requêtes JOIN sur la même table

    28 juillet 2010 à 10:01:53

    Bonjour,

    J'ai une table LIVRE avec 1 champ "titre" et 3 champs GENRE : "idgenre_1", "idgenre_2", "idgenre_3" :
    TITRE idgenre_1 idgenre_2 idgenre_3
    MYSERY / 1 / 2 / 3

    Une relation doit être faite avec une table GENRE qui comporte un champ "id_genre" et un champ "nom_genre" :
    id_genre nom_genre
    1 Fantastique
    2 Horreur
    3 thriller

    Je souhaite afficher le livre ayant les 3 genres de la façon suivante :
    MISERY
    Fantastique
    Horreur
    thriller

    Mais la requête suivante n'aboutit pas :
    SELECT genre.nom_genre, livre.titre
    FROM livre
    INNER JOIN genre ON genre.id_genre = livre.idgenre_1 
    INNER JOIN genre ON genre.id_genre = livre.idgenre_2
    INNER JOIN genre ON genre.id_genre = livre.idgenre_3
    LIMIT 0 , 100
    

    J'ai l'erreur suivante : "#1066 - Not unique table/alias: 'genre'"
    Voyez-vous une autre solution pour aboutir au résultat escompté ? Merci d'avance.
    • Partager sur Facebook
    • Partager sur Twitter
      28 juillet 2010 à 10:59:44

      SELECT genre.nom_genre, livre.titre
      FROM livre
      INNER JOIN genre ON genre.id_genre IN (livre.idgenre_1, livre.idgenre_2, livre.idgenre_3)
      

      NOM_GENRE            TITRE                
      -------------------- -------------------- 
      Fantastique          MISERY               
      Horreur              MISERY               
      Epouvante            MISERY               
      
      3 rows selected


      Avis aux plus initiés du SQL : possible de ramener le titre du livre, et le nom des genres sur une seule ligne ou faut-il changer la structure des tables ?

      Edit : j'ai trouvé :
      SELECT livre.titre,
      (SELECT nom_genre FROM genre WHERE id_genre = livre.idgenre_1) AS genre1,
      SELECT nom_genre FROM genre WHERE id_genre = livre.idgenre_2) AS genre2,
      SELECT nom_genre FROM genre WHERE id_genre = livre.idgenre_3) AS genre3
      FROM livre
      

      TITRE                GENRE1               GENRE2               GENRE3               
      -------------------- -------------------- -------------------- -------------------- 
      MISERY               Fantastique          Horreur              Epouvante            
      
      1 rows selected
      • Partager sur Facebook
      • Partager sur Twitter
        28 juillet 2010 à 11:38:18

        Tant qu'il y a des correspondances entre les tables on peux récupérer tout les résultats de la jointure des deux tables, oui. ;)

        Mais effectivement il serrait préférable de modifier la structure des tables, dans l'absolu il faudrait trois tables, une table 'livre' (livre_id, autres_infos...), une table 'livre_genre' (livre_id, genre_id) et une table 'genre' (genre_id, genre_nom).

        Ensuite il suffirait d'ajouter un livre, qui aurait donc un livre_id unique et de simplement remplir la table 'livre_genre' pour ajouter des valeurs avec l'id du livre et l'id du genre à ajouter, on peux ainsi avoir un nombre de genre par livre illimité et optimisé en fonction de chaque livre. ;)

        Sinon, l'erreur de ta requête viens du fait que tu JOIN 3 fois la même table et que tu utilise le même nom de table dans les clauses ON du coups MySQL ne sait plus quelles table utiliser pour la jointure, la requête de VirtualBlueRat devrait donc régler le problème, sinon il faut mettre des alias pour éviter l'erreur.

        Mais autant utiliser une méthode optimisée ;) .
        • Partager sur Facebook
        • Partager sur Twitter
        - Activer les erreurs : PHP - PDO - MYSQLI - ¯\_ツ_/¯ - Documentations : PHP - MySQL -
          28 juillet 2010 à 13:40:30

          Merci à VirtualBlueRat pour sa requête, elle revoie le résultat que je souhaitais.

          Citation : Sombrelune



          Mais effectivement il serrait préférable de modifier la structure des tables, dans l'absolu il faudrait trois tables, une table 'livre' (livre_id, autres_infos...), une table 'livre_genre' (livre_id, genre_id) et une table 'genre' (genre_id, genre_nom).



          Ta suggestion est pertinente car initialement j'avais créé 3 tables :
          - 1 table LIVRE comportant notamment comme champs : ID_LIVRE et TITRE
          - 1 table GENRE comportant comme champs : ID_GENRE et NOM_GENRE
          - 1 table THEMATISE comportant comme champs : ID_LIVRE et ID_GENRE

          J'utilisais la requête suivante :
          SELECT L.titre, G.nom_genre
          FROM livre L
          INNER JOIN thematise T
              ON T.id_livre = L.id_livre
          INNER JOIN genre G
              ON T.id_genre = G.id_genre
          


          Un livre pouvant appartenir à plusieurs genres, 1000 lignes(livres) m'étaient retournées (alors que ma base ne contient que 800 livres).Dans ma page PHP, il y avait donc autant d'occurrences du même livre que de genres auquel appartenait ce livre :
          ex : 1- "LE FLEAU"
          Horreur
          2- "LE FLEAU"
          Thriller
          Mais ce n'était pas l'affichage que je souhaitais. En fait je voulais obtenir l'affichage que j'obtiens grâce à la requête de VirtualBlueRat, mais au prix de l'abandon de la table THEMATISE (et de l'ajout de champs idgenre_1... dans la table livre).
          Je préférerais conserver mes 3 tables mais je n'arrive pas à gérer le traitement PHP pour arriver à l'affichage souhaité. Je te renvoie au message que j'ai posté sur le forum PHP :
          http://www.siteduzero.com/forum-83-543605-p1-2-requetes-et-boucles-while.html#r5230313
          

          Par ailleurs, on m'a conseillé de faire "au préalable une requête qui ramène toutes les catégories et les liens entre les livres et les catégories. Puis de stocker le tout dans un tableau associatif de façon à pouvoir l'interroger depuis la boucle while :
          ex : array ( idLivre1 => (cat1, cat3), idLivre2 => (cat1), ...) Pour chacun de mes livres, je pourrais alors récupérer le tableau de catégories associé à son id."

          Qu'en penses-tu ? tu me répondre plutôt sur le message posté sur le forum PHP si ta réponse dépasse le cadre SQL. Merci d'avance.
          • Partager sur Facebook
          • Partager sur Twitter
            28 juillet 2010 à 14:16:48

            Le soucis avec ma requête c'est qu'elle est statique, tu as un nombre défini de genres (ici 3).
            Il faudra donc penser à une autre requête si tu optes pour cette structure à 3 tables.
            Après tout dépend comment tu comptes afficher le tout, dans un tableau je suppose ? Tous les genres dans une seule colonne ?
            Dans ce cas tu pourrais faire une boucle en PHP avec ta requête :
            SELECT L.titre, G.nom_genre
            FROM livre L
            INNER JOIN thematise T
                ON T.id_livre = L.id_livre
            INNER JOIN genre G
                ON T.id_genre = G.id_genre
            

            ce qui donnerait :
            <?php
            $flag = true;
            while($donnees = $requete->fetch())
            {
                if($flag == false && $titre != $donnees['titre'])
                {
                    echo '</td></tr>';
                    $flag = true;
                }
            
                if($flag == true)
                {
                    $titre = $donnees['titre'];
                    echo '<tr>';
                    echo '<td>'.$titre.'</td>';
                    echo '<td>'.$donnees['nom_genre'];
                    $flag = false;
                }
                elseif($flag == false && $donnees['titre'] == $titre)
                {
                    echo '<br />'.$donnees['genre'];
                }
            }
            


            Dans cet esprit là, tu as un 'flag' (un drapeau), s'il est à TRUE tu affiches le titre du livre sur une nouvelle ligne dans la première colonne du tableau, ensuite dans la seconde colonne tu affiches le genre, on positionne le flag à FALSE.
            Prochain tour de boucle, on imagine que tu es toujours sur le même livre mais avec un autre genre (car ce livre possède 3 genres). Comme le flag est à FALSE, tu sautes le IF et tu vas dans le ELSEIF, on compare que c'est toujours le même livre grâce à la variable $livre, puis on ajoute l'autre genre en dessous du premier.
            Autre tour de boucle, même histoire ...
            Tour de boucle qui suit, le flag est toujours à FALSE, mais le livre est différent, alors on ferme la ligne du tableau, et met le flag à TRUE pour recommencer une nouvelle ligne.

            ATTENTION : pense à mettre un ORDER BY titre dans ce cas là.

            Bien sûr ce que j'ai écris là je ne l'ai pas testé, j'espère qu'il n'y a pas d'erreur d'algorithme ou de syntaxe.

            Pour ma culture, si quelqu'un a une requête qui affiche en une ligne le titre du livre et le nom de ses genres (comme j'ai fait au-dessus) sachant qu'ils peuvent être variables, en prenant compte le schéma des 3 tables : je suis preneur !

            EDIT : Sinon plus simple, comme l'a énoncé Lord Casque Noir sur un autre topic, si tu as MySQL tu peux utilisé GROUP_CONCAT, c'est exactement ce qu'il te faudrait ici !
            Regarde c'est assez simple d'utilisation : http://www.mysqlperformanceblog.com/20 [...] by-extension/
            • Partager sur Facebook
            • Partager sur Twitter
              28 juillet 2010 à 20:07:41

              Merci beaucoup VirtualBlueRat pour tous ces éléments de réponse ;)
              • Partager sur Facebook
              • Partager sur Twitter

              Requêtes JOIN sur la même table

              × 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