Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème requête SQL avec plusieurs jointures

Sujet résolu
    2 janvier 2020 à 11:33:24

    Bonjour à tous,

    J'ai une base de données composée de 3 tables : 

         Cable  (id_cable)

         Fibre (id_fibre, id_cable)

         Position(id_position, id_fibre1, id_fibre2) 

    Ces 3 tables sont reliées de la sorte : chaque câble possèdent des fibres, qui sont elles-mêmes situées dans des "positions".

    Je dois écrire une requête me permettant d'obtenir, pour chaque câble, le nombre de fois où une fibre lui appartenant apparaît dans "id_fibre1" et "id_fibre2".

    Je devrais donc obtenir quelque chose dans le genre : 

         Cable     NbdeFibre_idfibre1     NbdeFibre_idfibre2

         1                   24                                 6

         2                   32                                48

         3                   32                                21

    Pour l'instant, ma requête ressemble à ça : 

    SELECT cable.id_cable, COUNT(position.id_fibre1), COUNT (position.id_fibre2)
    FROM cable
    INNER JOIN fibre ON cable.id_cable = fibre.id_cable
    INNER JOIN position ON fibre.id_fibre = position.id_fibre1
    INNER JOIN position ON fibre.id_fibre = position.id_fibre2
    GROUP BY cable.id_cable

    Et j'obtiens ce message : 

         ERREUR:  le nom de la table « t_position » est spécifié plus d'une fois

    Je comprend bien que le problème vient du fait que dans ma requête, "INNER JOIN position" apparaît 2 fois. J'arrive à avoir, pour chaque câble, le nombre de fibre qui apparaît dans "id_fibre1" ou dans "id_fibre2", mais je n'arrive pas à avoir ces 2 informations en même temps

    -
    Edité par Luffygaya 2 janvier 2020 à 11:55:32

    • Partager sur Facebook
    • Partager sur Twitter
      2 janvier 2020 à 13:01:42

      Bonjour,

      Pour utiliser plusieurs fois la même table il faut lui donner des alias différents. Dans ton cas :

      SELECT
      	C.id_cable,
      	COUNT( P1.id_fibre1 ),
      	COUNT( P2.id_fibre2 )
      FROM
      	cable C
      		INNER JOIN fibre F
      			ON C.id_cable = F.id_cable
      		INNER JOIN position P1
      			ON F.id_fibre = P1.id_fibre1
      		INNER JOIN position P2
      			ON F.id_fibre = P2.id_fibre2
      GROUP BY C.id_cable

      Mais cela ne résoudra pas ton problème, car cette syntaxe imposerait qu'une fibre soit à la fois fibre1 et fibre2 ... ce qui n'est pas possible ...

      Tu vas devoir décomposer ton besoin en deux requêtes.

      Une pour fibre1 :

      -- Nombre de fibre1 par cable
      SELECT
      	C.id_cable,
      	COUNT(*) nb_fibre_1
      FROM
      	cable C
      		INNER JOIN fibre F
      			ON C.id_cable = F.id_cable
      		INNER JOIN position P
      			ON F.id_fibre = P.id_fibre1
      GROUP BY C.id_cable

      Et une pour fibre 2 :

      -- Nombre de fibre2 par cable
      SELECT
      	C.id_cable,
      	COUNT(*) nb_fibre_2
      FROM
      	cable C
      		INNER JOIN fibre F
      			ON C.id_cable = F.id_cable
      		INNER JOIN position P
      			ON F.id_fibre = P.id_fibre2
      GROUP BY C.id_cable

      Enfin, pour tout regrouper en une seule requête :

      SELECT
      	C.id_cable,
      	COALESCE( F1.nb_fibre_1, 0 ) AS fibre1
      	COALESCE( F2.nb_fibre_2, 0 ) AS fibre2
      FROM
      	cable C
      		LEFT JOIN (
      				-- Nombre de fibre1 par cable
      				SELECT
      					C.id_cable,
      					COUNT(*) nb_fibre_1
      				FROM
      					cable C
      						INNER JOIN fibre F
      							ON C.id_cable = F.id_cable
      						LEFT JOIN position P
      							ON F.id_fibre = P.id_fibre1
      				GROUP BY C.id_cable
      			) F1
      			ON C.id_cable = F1.id_cable
      		LEFT JOIN (
      				-- Nombre de fibre2 par cable
      				SELECT
      					C.id_cable,
      					COUNT(*) nb_fibre_2
      				FROM
      					cable C
      						INNER JOIN fibre F
      							ON C.id_cable = F.id_cable
      						LEFT JOIN position P
      							ON F.id_fibre = P.id_fibre2
      				GROUP BY C.id_cable
      			) F2
      			ON C.id_cable = F2.id_cable

      Une solution plus normalisée aurait été de créer une table de relation entre position et fibre...

      • cable ( id_cable [pk], etc. )
      • fibre ( id_fibre [pk], id_cable [fk], etc. )
      • position ( id_position [pk], etc. )
      • position_fibre ( id_position [pk][fk], id_fibre [pk][fk], ordre ) avec UNIQUE( id_position, id_fibre, ordre )

      Avec ce modèle la requête te permettant de savoir par câble et par ordre le nombre de fibres existantes :

      SELECT
      	C.id_cable,
      	P.ordre,
      	COUNT(*) AS nb_fibres
      FROM
      	cable C
      		INNER JOIN fibre F
      			ON C.id_cable = F.id_cable
      		INNER JOIN position_fibre PF
      			ON F.id_fibre = PF.id_fibre
      GROUP BY
      	C.id_cable,
      	P.ordre

      Cela te permet d'avoir plus de deux fibres par position (je ne sais pas si c'est intéressant), mais aussi de n'avoir qu'une seule fibre par position ou aucune, sans occuper de place superflue en base ...

      -
      Edité par Benzouye 2 janvier 2020 à 13:08:23

      • Partager sur Facebook
      • Partager sur Twitter
      Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
        2 janvier 2020 à 15:16:46

        Merci pour ta réponse, c'est sympa d'avoir autant détaillé ton explication.

        Instinctivement, j'aurais eu tendance à écrire ma requête comme la 1ère que tu as écrite, en donnant des alias différent à ma table "position" pour pouvoir l'utiliser plusieurs fois.

        Mais j'ai fais quelques tests, et effectivement les résultats sont faux. J'ai encore du mal à comprendre pourquoi, mais je vais prendre le temps de relire ton explication et cette histoire de fibre qui devrait être à la fois fibre1 et fibre 2 (cela faisait un moment que je n'avais pas fais de SQL, je dois me remettre dans le bain).

        La requête finale marche nickel, les résultats obtenus sont justes. Encore merci pour ton aide.

        Quant à modifier la base de données en créant et/ou modifiant certaines tables, ce n'ai pas quelques chose que je peux faire avec mon statut actuel. Mais j'en toucherait peut-être un mot à mes collègues, histoire de savoir pourquoi cette table de relation entre position et fibre n'a pas été créée.

        • Partager sur Facebook
        • Partager sur Twitter

        Problème requête SQL avec plusieurs jointures

        × 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