Partage
  • Partager sur Facebook
  • Partager sur Twitter

Jointure OU NOT EXISTS

Sujet résolu
    30 juin 2020 à 11:12:12

    Bonjour à tous,

    Je me heurte encore à un problème qui serait de faire des jointures avec des enregistrement qui n'existe pas. . . ; Explications : 

    Le but de ma BDD est de lister des participants à des championnats E-sport. Lorsqu'il s'inscrit à un événement, je remplis cette table : 

    Lorsqu'il participe à une course (où le but et de faire un tour le plus rapidement possible = hotlap ) et qu'il envoie un temps, mon script crée un enregistrement dans la table Gain_pts_manche. Si le joueur refait un meilleur temps, je fait un update, si la personne ne fait pas de temps, aucune ligne ne se créer dans la table. L'enregistrement se fait ainsi :

    Afin de faire un classement, je suis quand même obliger de donner un résultat aux joueurs qui ne font pas de temps, sinon ils apparaissent en premier alors qu'il sont derniers ou alors ils n'apparaissent pas car la jointure en INNER ne les sélectionnent pas. 

    J'aimerais donc trouver une requête SQL qui m'affiche tous les joueurs qui n'ont pas fait de temps en prenant la liste des participants de ce championnat ( et de la manche en particulier car un joueur peux faire un temps pour un manche et pas pour une autre par exemple ). Quelque chose comme : 

    Le participant 3 apparait dans les deux table donc il est ignoré mais le participant 2 lui n'apparait que dans Participants et pas dans l'autre donc on l'affiche. La requête renvoie les id_participant qui ne sont pas dans Gain_pts_manche et je me sert des ces id pour leur mettre une pénalité dans une autre requête.

    J'avais donc pensé aux jointures mais elle fonctionneraient si j'avais des ligne NULL en face mais là je n'ai pas de ligne. Et avec NOT EXISTS j'ai mes deux lignes mais je n'arrive pas à les trier car mes options de tri ne sont pas dans la table Participants. . . 

    SELECT * FROM `Participants` 
    WHERE id_championnat = 50 AND NOT EXISTS 
    ( SELECT id_participant FROM Gain_pts_manche 
    WHERE Gain_pts_manche.id_manche=21 AND Gain_pts_manche.temps_hotlap != NULL)

    J'ai testé ceci mais sans succès. Si vous avez une piste ou un coup de pouce je suis preneur ^^

    Merci

    -
    Edité par Community Technologie 30 juin 2020 à 11:13:49

    • Partager sur Facebook
    • Partager sur Twitter

    Désolé, mais je ne vois pas mes erreurs

    www.community-technologie.fr 

      Staff 30 juin 2020 à 11:32:24

      Bonjour,

      Je ne suis pas sûr de comprendre la question. Selon moi tu devrais tout pouvoir faire en une seule requête ... c'est le principe même des jointures ... et des jointures externes ...

      Après il y a quelque chose qui me chagrine, c'est le fait qu'il semble y avoir des colonnes calculées (comme total_points).

      Peux-tu nous décrire un peu plus ton modèle, et notamment les tables participant, championnat et manche ? Je suppose qu'il il y a un lien entre manche et championnat ?

      • Partager sur Facebook
      • Partager sur Twitter
      Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
        30 juin 2020 à 12:56:27

        Benzouye a écrit:

        Après il y a quelque chose qui me chagrine, c'est le fait qu'il semble y avoir des colonnes calculées (comme total_points).

        Total_point ne concerne pas ce type de championnat ( Si un joueur arrive premier à une course il gagne 100 pts, lorsqu'il arrive second à la deuxième course il gagne 90 pts, un script additionne les enregistrement de Gain_pts_manche et update total_point à 190. )

        Mon modele est le suivant : (ne pas faire attention au cardinalitée et FK j'ai fait ça vite fait... ) 

        Et oui il y a un lien entre manche et championnat, un championnat contient plusieurs manche.

        Voici plus en détail ma table Gain_pts_manche

        Le premier enregistrement concerne les courses à plusieurs joueurs avec un classement et un nombre de points (mais ce n'est pas lui qui m'intéresse ) 

        Le deuxième et celui qui doit matcher avec la table Participants.

        Que n'as-tu pas compris dans le problème ? j'essaie de reformuler :

        Si le joueur avec l'id 3 participe au championnat, mais que dans Gain_pts_manche je n'ai pas de ligne avec l'id 3 pour une manche de ce championnat, cela veux dire qu'il n'a pas participé, la requête doit donc afficher son id pour que je puisse lui mettre une pénalité. S'il a participé, la requête trouve une correspondance et ignore le joueur car je n'ai rien à faire de spéciale avec les joueurs qui ont participé

        Merci

        • Partager sur Facebook
        • Partager sur Twitter

        Désolé, mais je ne vois pas mes erreurs

        www.community-technologie.fr 

          Staff 30 juin 2020 à 14:08:05

          Pour lister les participants à un championnat donné, avec leur hotlap si existant :

          SELECT
          	U.pseudo,
          	P.id_participant,
          	M.id_manche,
          	G.temps_hotlap
          FROM
          	participants P
          		INNER JOIN users U
          			ON P.id_participant = U.id_user
          		INNER JOIN manche M
          			ON P.id_championnat = M.id_championnat
          		LEFT JOIN Gain_pts_manche G
          			ON M.id_manche = G.id_manche
          			AND P.id_participant = G.id_participant
          WHERE
          	P.id_championnat = 50

          Cette requête va te lister tous les couples joueur / manche pour le championnat donné (ici 50). Et si ils ont un hotlap celui-ci s'affichera, sinon ce sera NULL. Tu peux utiliser COALESCE pour choisir quoi afficher si NULL (0 ou -1 ou 200:00:00, etc.).

          • Partager sur Facebook
          • Partager sur Twitter
          Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
            30 juin 2020 à 14:31:09

            J'ai remis a ma sauce et voila ce que j'obtiens : 

            SELECT
                Participants.id_participant,
                Manches.id_manche,
                Gain_pts_manche.temps_hotlap
            FROM
                Participants
                    INNER JOIN Manches
                        ON Participants.id_championnat = Manches.id_championnat
                    LEFT JOIN Gain_pts_manche
                        ON Manches.id_manche = Gain_pts_manche.id_manche
                        AND Participants.id_participant = Gain_pts_manche.id_participant
            WHERE
                Participants.id_championnat = 50

            J'obtiens bien un couple. Lorsque je modifie ma clause en remplaçant Participants.id_championnat = 50 par 

             Manches.id_manche = 21

            J'obtiens

              
             
            mais pas moyen de retirer l'id 3 car lui il matches bien. Si dans ma clause je met

            Manches.id_manche = 21 AND Gain_pts_manche.temps_hotlap = NULL

            je perd tout, mais 

            Manches.id_manche = 21 AND Gain_pts_manche.temps_hotlap != 0

            me donne bien l'id 3 SEUL, mais = 0 ne me renvoie rien

            • Partager sur Facebook
            • Partager sur Twitter

            Désolé, mais je ne vois pas mes erreurs

            www.community-technologie.fr 

              Staff 30 juin 2020 à 14:54:38

              Je ne comprends pas pourquoi tu veux retirer le 3 ... Je pensais que tu cherchais à faire une requête pour faire un classement et que tu étais parti pour le faire en deux requêtes, une pour ceux qui ont fait la course et une pour ceux qui ne l'ont pas fait ... Je te proposais ici de faire cela en une seule fois ...

              Community Technologie a écrit:

              Si dans ma clause je met

              Manches.id_manche = 21 AND Gain_pts_manche.temps_hotlap = NULL

              je perd tout

              Oui car en SQL ma_colonne = NULL est TOUJOURS faux. Même NULL = NULL retourne faux ...

              Pour comparer à NULL, il faut utiliser IS NULL ou IS NOT NULL. Dans ton cas :

              WHERE temps_hotlap IS NULL

              -
              Edité par Benzouye 30 juin 2020 à 14:55:27

              • Partager sur Facebook
              • Partager sur Twitter
              Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                30 juin 2020 à 21:28:52

                Ah non pardon, le classement et fait par une autre requête 

                Bizarre pour les = NULL car il m'arrive d'utiliser = NULL ou != NULL et ça fonctionne très bien dans mes cas. J'utiliserais is / IS NOT du coup.

                Et effectivement avec : 

                WHERE temps_hotlap IS NULL

                cela fonctionne et m'affiche bien mes lignes. Merci Benzouye

                • Partager sur Facebook
                • Partager sur Twitter

                Désolé, mais je ne vois pas mes erreurs

                www.community-technologie.fr 

                  Staff 1 juillet 2020 à 0:09:21

                  NULL signifie "absence de valeur" donc rien ne peut être égal ou différent de quelque chose qui n'existe pas ...

                  Cela ne peut donc pas fonctionner "dans tes cas" ... sauf si tu veux toujours avoir FALSE en retour ... mais ce serait absurde ...

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL

                  Jointure OU NOT EXISTS

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  • Editeur
                  • Markdown