Partage
  • Partager sur Facebook
  • Partager sur Twitter

Requête MySQL sur deux tables sans jointure

Sujet résolu
    3 janvier 2018 à 1:10:56

    Salut à touTEs,
    j'ai une table films, et une table acteurs. Chaque film comporte plusieurs acteurs, et chaque acteur a possiblement joué dans plusieurs films.
    Pour l'instant dans la table films j'ai mis les champs acteur_a , acteur_b , acteur_c, etc , en ayant l'intention d'y insérer les id de la table acteurs. J'ai l'impression que ce n'est pas une bonne manière de m'organiser mais je n'ai pas encore trouvé une meilleure option.
    Avec while j'affiche les valeurs de chaque champ d'un film (titre, année, durée, etc) et je dois également afficher les noms des acteurs qui jouent dans le film.
    Mais je n'arrive pas à écrire la requête correctement, pour les raisons suivantes :
    - Je n'arrive pas à faire une jointure étant donné que les id des acteurs peuvent correspondre à plusieurs champs (acteur_a , acteur_b , acteur_c, etc ) 
    - J'ai besoin de sélectionner uniquement les acteurs qui jouent dans le film, et la quantité d'acteurs par film varie d'un film à l'autre.
    J'ai donc besoin non seulement d'afficher les données d'un film une par une avec une boucle while, mais également d'afficher les données "hors boucle" (je ne sais pas si je suis clair, je ne connais pas le terme exact) de la table acteur via l'id de chaque acteur concerné.
    Bref il faut que ma requête combine à la fois ce qui doit être sélectionné pour le while mais également des valeurs "autonomes" d'une autre table.
    Par avance merci de vos pistes de réflexion :)

    -
    Edité par HugoSweetPotato 3 janvier 2018 à 1:12:58

    • Partager sur Facebook
    • Partager sur Twitter
      3 janvier 2018 à 2:45:57

      En effet ce n'est pas la bonne méthode dans ce genre de cas tu dois passer par une table intermédiaire que j'ai appelé "Contrat", cette table lie l'identifiant d'un film et l'identifiant d'un acteur

        

      Les champs refIdFilm et refIdActeur sont des clé étrangère qui font respectivement références aux clés primaires idFilm et idActeur

      Ainsi donc pour ce qui est de la requête SQL :

      SELECT NomActeur FROMActeurJOINContratONActeur.idActeur=Contrat.refIdActeurJOINFilmONFilm.idFilm=contrat.refIdFilmWHERE NomFilm="YourName"

      • Partager sur Facebook
      • Partager sur Twitter
        3 janvier 2018 à 9:23:55

        Bonjour,

        PheniXosBurn a écrit:

        En effet ce n'est pas la bonne méthode dans ce genre de cas tu dois passer par une table intermédiaire que j'ai appelé "Contrat"

        Même si Hugo n'est pas parti du bon pied, tu l'orientes de travers Phenix ...

        Si l'on applique la méthode de modélisation entité / relation (cf. doc "Conception BDD" dans ma signature), alors :

        HugoSweetPotato a écrit:

        j'ai une table films, et une table acteurs. Chaque film comporte plusieurs acteurs, et chaque acteur a possiblement joué dans plusieurs films

        Phenix propose de créer une troisième entité contrat ... Ce qui aura pour défaut de permettre de stocker plusieurs fois le même couple film/acteur dans la base ...

        Je te propose ceci : tu as deux entités film et acteur. Deux entités donc deux tables.

        Ensuite tu as une relation n,n (plusieurs à plusieurs) entre ces deux entités. Ceci qui implique une table de relation.

        Le modèle de données sera donc :

        • film ( id_film [pk], titre, etc. ) pour stocker les films
        • acteur ( id_acteur [pk], nom, prenom, etc. ) pour stocker les acteurs
        • participation ( id_film [pk][fk], id_acteur [pk][fk] ) pour lier un acteur à un film

        Après tu peux compliquer un peu le modèle en ajoutant la notion de métier ... Une personne peut intervenir plusieurs fois sur le même film mais avec des métiers différents (acteur et réalisateur par exemple). Le modèle devient alors :

        • film ( id_film [pk], titre, etc. ) pour stocker les films
        • personne ( id_personne [pk], nom, prenom, etc. ) pour stocker les personnes
        • metier ( id_metier [pk], libelle ) pour stocker les métiers possibles
        • participation ( id_film [pk][fk], id_personne [pk][fk], id_metier [pk][fk] ) pour lier une personne à un film avec un métier
        • Partager sur Facebook
        • Partager sur Twitter
        Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
          3 janvier 2018 à 18:50:51

          Merci beaucoup PheniXosBurn et Benzouye pour ces indications !

          Je récapitule pour vérifier si j'ai bien compris :

          La principale différence entre vos deux propositions est que dans celle de Benzouye la nouvelle table n'a pas une colonne primaire dédiée à l'id mais a deux clés primaires, ce qui permet d'éviter les doublons. Est-ce juste ?

          Cependant, il me semblait qu'une table ne peut avoir qu'une seule clé primaire, comme expliqué dans ce cours : https://openclassrooms.com/courses/administrez-vos-bases-de-donnees-avec-mysql/cles-primaires-et-etrangeres

          -
          Edité par HugoSweetPotato 3 janvier 2018 à 21:18:25

          • Partager sur Facebook
          • Partager sur Twitter
            4 janvier 2018 à 8:57:18

            HugoSweetPotato a écrit:

            dans celle de Benzouye la nouvelle table n'a pas une colonne primaire dédiée à l'id mais a deux clés primaires

            Pas deux clés primaires (ce n'est en effet pas possible), mais une clé primaire composée de deux colonnes.

            -
            Edité par Benzouye 4 janvier 2018 à 8:57:30

            • Partager sur Facebook
            • Partager sur Twitter
            Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
              4 janvier 2018 à 19:07:00

              Est-ce que la nouvelle table pourrait être comme ça ?

              CREATE TABLE lien_acteur_film (fk_id_acteur INT NOT NULL, fk_id_film INT NOT NULL,
              PRIMARY KEY (fk_id_acteur,fk_id_film),
              INDEX (fk_id_acteur,fk_id_film),
              FOREIGN KEY (fk_id_acteur,fk_id_film),
              REFERENCES (acteur(acteur_id), film(film_id))
              ON UPDATE CASCADE ON DELETE RESTRICT) TYPE=INNODB



              • Partager sur Facebook
              • Partager sur Twitter
                5 janvier 2018 à 9:56:54

                Non :p

                La clé primaire sera composée, mais pas les clés étrangères. Au passage, il ne sert à rien de mettre un index identique à la clé primaire qui est déjà une sorte d'index.

                CREATE TABLE lien_acteur_film (
                	fk_id_acteur INT NOT NULL,
                	fk_id_film INT NOT NULL,
                	PRIMARY KEY (fk_id_acteur,fk_id_film),
                	INDEX (fk_id_acteur),
                	INDEX (fk_id_film),
                	FOREIGN KEY fk_id_acteur REFERENCES acteur(acteur_id),
                	FOREIGN KEY fk_id_film REFERENCES film(film_id)
                ) TYPE=INNODB
                • Partager sur Facebook
                • Partager sur Twitter
                Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                  6 janvier 2018 à 17:26:08

                  Merci Benzouye,

                  tout ça est encore extrêmement flou pour moi. Je vais potasser ton cours de conception BDD histoire de mieux comprendre ces subtilités.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    11 janvier 2018 à 17:15:46

                    Bonsoir à touTEs,

                    j'ai attentivement suivi le cours de conception BDD et j'ai créé la table de relation dont je saisis beaucoup mieux le rôle. Mais maintenant en ce qui concerne le passage à l'action, je sèche totalement.

                    Je ne comprends pas avec quoi la remplir, ni quelle forme pourrait prendre la requête pour afficher les acteurs d'un film, bref je suis paumé.

                    Serait-il possible que vous m'orientez un peu pour que je puisse sortir de cette ornière ? J'ai pour habitude de m'auto-former mais là je ne sais vraiment pas par où commencer... :euh:

                    Par avance merci pour toute indication :)

                    • Partager sur Facebook
                    • Partager sur Twitter
                      11 janvier 2018 à 17:22:56

                      Bonjour,

                      La table de relation comprendra simplement l'id du film correspondant à l'id de l'acteur.

                      • Partager sur Facebook
                      • Partager sur Twitter
                        18 janvier 2018 à 18:19:21

                        Bonjour à touTEs,

                        grâce à vos indications je commence très doucement à comprendre comment ça s'articule. Mais je bloque sur ma première requête.

                        En effet, je voudrais tout d'abord afficher la liste des acteurs d'un film, j'ai donc essayé cette requête :

                        <?php
                        $req = $bdd->prepare('
                            SELECT *
                            FROM acteur, lien_acteur_film
                            WHERE lien_acteur_film.fk_id_film=?
                        ') 
                        or die(print_r($bdd->errorInfo()));
                        $req->execute(array($_GET['film_id'] 
                        ));
                        while ($donnees = $req->fetch())
                        {
                        ?>
                         Acteur :   <?php echo $donnees['fk_id_acteur']; ?><br>
                        <?php
                        }
                        $req->closeCursor();
                        ?>

                        Mais ce code affiche quatre fois la liste des acteurs du film sélectionné. Ce qui semble venir du fait qu'il y a 4 acteurs dans la table lien_acteur_film, mais je ne vois pas comment m'affranchir de ce premier problème (il y en aura d'autres :p).

                        Par avance merci de votre aide :)

                        -
                        Edité par HugoSweetPotato 18 janvier 2018 à 18:21:03

                        • Partager sur Facebook
                        • Partager sur Twitter
                          18 janvier 2018 à 18:52:50

                          Tu trouveras les bases ici : https://openclassrooms.com/courses/introduction-aux-jointures-sql

                          Je te conseille de rester sur ce que le rédacteur appelle la "nouvelle syntaxe" :

                          $req = $bdd->prepare('
                              SELECT *
                              FROM acteur INNER JOIN lien_acteur_film ON acteur.id=fk_id_acteur
                          	INNER JOIN film ON fk_id_film=film.id
                          	WHERE film.id=?
                          ');



                          -
                          Edité par philodick 18 janvier 2018 à 18:53:13

                          • Partager sur Facebook
                          • Partager sur Twitter
                            19 janvier 2018 à 12:43:33

                            Bonjour Philodick, et merci infiniment !

                            C'est exactement le tutoriel que je cherchais depuis fort longtemps, et ton code est celui qu'il me manquait. Il y avait juste quelques petites coquilles, alors je le remets ici :

                            $req = $bdd->prepare('
                                SELECT *
                                FROM acteur INNER JOIN lien_acteur_film ON acteur_id=fk_id_acteur
                                INNER JOIN film ON fk_id_film=film_id
                                WHERE film_id=?
                            ');

                            Merci beaucoup à touTEs pour votre aide précieuse !

                            • Partager sur Facebook
                            • Partager sur Twitter
                              19 janvier 2018 à 15:40:48

                              Mon code n'était qu'un exemple, je n'avais pas l'intitulé exact de tes colonnes ;)
                              • Partager sur Facebook
                              • Partager sur Twitter
                                19 janvier 2018 à 15:51:21

                                Ah, et j'ai aussi une dernière question :

                                Est-ce qu'une jointure dans un sens est équivalente à une jointure dans l'autre sens ?

                                Exemple :

                                Est-ce que 

                                    FROM film
                                    INNER JOIN lien_acteur_film ON film_id=fk_id_film
                                    INNER JOIN acteur ON fk_id_acteur=acteur_id

                                donnera les mêmes résultats que 

                                    FROM acteur 
                                    INNER JOIN lien_acteur_film ON acteur_id=fk_id_acteur
                                    INNER JOIN film ON fk_id_film=film_id



                                ?


                                -
                                Edité par HugoSweetPotato 19 janvier 2018 à 15:51:49

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  19 janvier 2018 à 15:55:39

                                  Tu le verrais avec un simple test... Dans ce cas là, oui. Ce serait différent avec des jointures externes (LEFT JOIN ou RIGHT JOIN).
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    20 janvier 2018 à 0:05:53

                                    Oui je l'avais testé et remarqué mais j'avais peur d'avoir loupé une subtilité :)

                                    Autre question, j'ai ma requête qui me permet d'afficher avec while tous les films un par un :

                                    $req = $bdd->prepare('
                                        SELECT *
                                        FROM film
                                        LEFT JOIN lien_acteur_film ON film_id=fk_id_film
                                        LEFT JOIN acteur ON fk_id_acteur=acteur_id
                                        GROUP BY film_id
                                        ') 
                                    or die(print_r($bdd->errorInfo()));
                                    $req->execute(array());
                                    while ($donnees = $req->fetch())
                                    {
                                    ?>
                                        <h3><?php echo $donnees['film_titre']; ?> (<?php echo $donnees['film_annee']; ?>)</h3>
                                        <?php echo $donnees['acteur_nom'];
                                    }
                                    $req->closeCursor(); // Termine le traitement de la requête
                                    ?>

                                    Problème : ça ne me renvoie qu'un seul acteur de chaque film.

                                    Ce que je voudrais c'est que chaque ligne de film affiche la liste de ses acteurs, alors j'ai essayé de mettre une nouvelle boucle (d'acteurs) à l'intérieur de la boucle (de films) :

                                    $req = $bdd->prepare('
                                        SELECT *
                                        FROM film
                                        LEFT JOIN lien_acteur_film ON film_id=fk_id_film
                                        LEFT JOIN acteur ON fk_id_acteur=acteur_id
                                        GROUP BY film_id
                                        ') 
                                    or die(print_r($bdd->errorInfo()));
                                    $req->execute(array());
                                    while ($donnees = $req->fetch())
                                    {
                                    ?>
                                        <h3><?php echo $donnees['film_titre']; ?> (<?php echo $donnees['film_annee']; ?>)</h3>
                                        <?php while ($donnees = $req->fetch())
                                        { echo $donnees['acteur_nom']; ?>, <?php } ?>
                                    <?php
                                    }
                                    $req->closeCursor(); // Termine le traitement de la requête
                                    ?>

                                    Mais maintenant, ça n'affiche que le premier film, et la liste des acteurs renvoie un acteur de chacun des autres films...

                                    -
                                    Edité par HugoSweetPotato 20 janvier 2018 à 12:48:23

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      20 janvier 2018 à 18:12:00

                                      Je te conseille de tester tes requêtes dans Phpmyadmin pour avoir incision globale. Si tu veux avoir les films avec la liste des acteurs, il faut rester sur la première requête avec INNER JOIN.

                                      Tu dois gérer l'affichage ensuite (en affichant le film que quand il est différent du précédant).

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        21 janvier 2018 à 14:36:02

                                        Ma première requête fonctionnait parfaitement car elle correspondait à une page du site où un seul film est sélectionné, maintenant je travaille sur l'index du site où l'on peut rechercher parmi tous les films.
                                        Je cherche donc à afficher une sélection des films en fonction de divers paramètres (durée, année...), et c'est bien la table film (sauf erreur) qui doit être "à gauche", notamment afin de pouvoir aussi afficher les films dont je n'ai pas encore rentré d'acteurs grâce au LEFT JOIN.
                                        La requête 
                                        SELECT *
                                            FROM film
                                            LEFT JOIN lien_acteur_film ON film_id=fk_id_film
                                            LEFT JOIN acteur ON fk_id_acteur=acteur_id
                                        me semble donc bonne, étant donné qu'elle sélectionne bien tout ce dont j'ai besoin. Le problème se situe au niveau de l'affichage, car elle m'affiche autant de films qu'il y a d'acteurs.
                                        C'est pourquoi j'ai ajouté "GROUP BY film_id" mais alors je n'ai plus qu'un seul acteur d'affiché par film.
                                        -----------------------------------------------------------------------------------------------------------------------
                                        Edit :
                                        Ça y est j'ai enfin trouvé, et ça fonctionne parfaitement !
                                        La solution était bien d'insérer une boucle dans la boucle, voici le code qui fonctionne :
                                        <?php     
                                        try
                                        {
                                        $bdd = new PDO('mysql:host=localhost;dbname=BDD;charset=utf8', 'toto', 'password',
                                        array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
                                        }
                                        catch (Exception $e)
                                        {
                                                die('Erreur : ' . $e->getMessage());
                                        }
                                        $req = $bdd->prepare('
                                            SELECT *
                                            FROM film
                                            LEFT JOIN lien_acteur_film ON film_id=fk_id_film
                                            LEFT JOIN acteur ON fk_id_acteur=acteur_id
                                            GROUP BY film_id
                                            ') 
                                        or die(print_r($bdd->errorInfo()));
                                        $req->execute(array());
                                        while ($donnees = $req->fetch())
                                        {
                                        ?>
                                            <h3><?php echo $donnees['film_titre']; ?></a> (<?php echo $donnees['film_annee']; ?>)</h3> 
                                        <!-- On établit la variable du film affiché pour la liste d'acteurs -->
                                            <?php $ligne_film=$donnees['film_id'] ?>
                                            <?php 
                                            $req2 = $bdd->prepare('
                                            SELECT *
                                            FROM acteur 
                                            INNER JOIN lien_acteur_film ON acteur_id=fk_id_acteur
                                            INNER JOIN film ON fk_id_film=film_id
                                            WHERE film_id='.$ligne_film.'
                                            ') 
                                            or die(print_r($bdd->errorInfo()));
                                            $req2->execute(array());
                                            while ($donnees2 = $req2->fetch()) { 
                                            echo $donnees2['acteur_nom'];?><br><?php
                                        }
                                            $req2->closeCursor(); // Termine le traitement de la 2eme requête
                                         ?>
                                            <br>
                                        <?php
                                        }
                                        $req->closeCursor(); // Termine le traitement de la 1ere requête
                                        ?>
                                        Est-ce que vous trouvez ça problématique, de faire une boucle dans une boucle ?

                                        -
                                        Edité par HugoSweetPotato 22 janvier 2018 à 15:27:42

                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Requête MySQL sur deux tables sans jointure

                                        × 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