IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage SQL Discussion :

Requête jointure sur 5 tables avec alternances d'externe et d'interne


Sujet :

Langage SQL

  1. #1
    Membre habitué Avatar de xess91
    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    408
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 408
    Points : 193
    Points
    193
    Par défaut Requête jointure sur 5 tables avec alternances d'externe et d'interne
    Bonjour à tous,

    Je suis sur un cas pratique de jointure afin de traiter des abonnements clients.
    Je vais essayer de donner le maximum d'infos et d'expliquer au mieux ce que je souhaite, en espérant ne rien oublier et ne pas faire d'erreurs de retranscription.

    Dans la problématique il peut y avoir plusieurs abonnements, ces abonnements ont des options (des critères propre) et des durées. Un abonnement peu avoir plusieurs durée (en mois dans mon cas).

    Il peut y avoir également des promotions sur un abonnement en fonction de sa durée.

    Le but est d'extraire tous les abonnements avec leurs options, leurs durées, leurs tarifications et leurs promotions si promotions il y a.

    Voici un exemple de deux abonnements identiques mais de durée différente dont l'un fait l'objet d'une promotion évènementielle: (voici ce que je souhaite obtenir à l'issue de la requête sql)

    Abonnement1:
    -critère A
    -critère B
    -critère C

    =>Durée 3 mois

    et

    Abonemment1:
    -critère A
    -critère B
    -critère C

    =>Durée 6 mois
    promotion spéciale un objet offert

    J'ai organisé le stockage de données en 5 tables :

    La première : contient le nom des abonnement
    La deuxième : contient les options (critères) pour chaque abonnement
    La troisième : contient les différentes durées pour chaque abonnement et la tarification
    La quatrième : contient la répartition des promotions et des quantités offerte par abonnement et durée d'abonnement
    La cinquième : contient la liste des objets promotionnels.

    J'ai fait un schéma des tables où les clefs de jointure sont colorisées :



    Voici la requête que j'ai mis en place avec un critère "WHERE id_tbl_abonnement = 1":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    SELECT 
    	*
    FROM
    		tbl_abonnement as a
    INNER JOIN
    		tbl_abo_opt as ao
    ON
    		a.id_tbl_abonnement = ao.id_abo_tbl_abo_opt
    INNER JOIN
    		tbl_abo_duree as ad
    ON
    		a.id_tbl_abonnement = ad.id_abo_tbl_abo_duree
    LEFT OUTER JOIN
    		tbl_opt_promo as op
    ON 
    		op.id_duree_tbl_opt_promo = ad.id_tbl_abo_duree
    INNER JOIN
    		tbl_opt_free as o
    ON 
    		o.id_tbl_opt_free = op.id_opt_tbl_opt_promo
    WHERE 
    		a.id_tbl_abonnement = '1'
    En se basant sur le schéma ci-dessus et ma requête voila ce que j'obtiens:

    Abo1:
    -Opt1
    -Opt2
    6mois - 18€
    N1 - D1
    N2 - D2

    L'Abo1 de 3 mois a été ignoré car il n'a pas de promotion d'ou l'intérêt de faire une jointure externe je pense.

    Voila ce que je souhaite obtenir :

    Abo1:
    -Opt1
    -Opt2
    6mois - 18€
    N1 - D1
    N2 - D2

    et

    Abo1:
    -Opt1
    -Opt2
    3mois - 10€

    Merci à tous pour votre aide.

  2. #2
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 879
    Points : 53 057
    Points
    53 057
    Billets dans le blog
    6
    Par défaut
    Apprenez à indentez correctement vos requête en montrant l'arborescence de jointure comme je l'indique ici : http://sqlpro.developpez.com/cours/s...ointures/#LV-B
    Vous comprendrez immédiatement votre faute :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    SELECT 	*
    FROM    tbl_abonnement AS a
            -- branche a/ao
            INNER JOIN tbl_abo_opt AS ao
                  ON a.id_tbl_abonnement = ao.id_abo_tbl_abo_opt
            -- branche a/ad      
            INNER JOIN tbl_abo_duree AS ad
                  ON a.id_tbl_abonnement = ad.id_abo_tbl_abo_duree
                  -- branche a/ad/op 
                  LEFT OUTER JOIN tbl_opt_promo AS op
                       ON ad.id_tbl_abo_duree = op.id_duree_tbl_opt_promo
                       -- branche a/ad/op/o
                       INNER JOIN tbl_opt_free AS o
                             ON op.id_opt_tbl_opt_promo = o.id_tbl_opt_free
    WHERE   a.id_tbl_abonnement = '1'
    En effet dans votre branche a/ad/op/o... vous passez d'une jointure externe (avant) à une jointure interne, ce qui annule l'effet de la jointure externe et revient à ne faire que des jointures internes.

    En principe en rectifiant votre requête comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    SELECT 	*
    FROM    tbl_abonnement AS a
            -- branche a/ao
            INNER JOIN tbl_abo_opt AS ao
                  ON a.id_tbl_abonnement = ao.id_abo_tbl_abo_opt
            -- branche a/ad      
            INNER JOIN tbl_abo_duree AS ad
                  ON a.id_tbl_abonnement = ad.id_abo_tbl_abo_duree
                  -- branche a/ad/op 
                  LEFT OUTER JOIN tbl_opt_promo AS op
                       ON ad.id_tbl_abo_duree = op.id_duree_tbl_opt_promo
                       -- branche a/ad/op/o
                       LEFT OUTER JOIN tbl_opt_free AS o
                             ON op.id_opt_tbl_opt_promo = o.id_tbl_opt_free
    WHERE   a.id_tbl_abonnement = '1'
    vous devriez obtenit la solution !

    Et pour un cours sur SQL, mon bouquin comme mon site peuvent vous aider...

    A +

  3. #3
    Membre habitué Avatar de xess91
    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    408
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 408
    Points : 193
    Points
    193
    Par défaut
    Merci beaucoup pour votre réponse,

    Effectivement je suis d'accord avec vous mon savoir est limité, c'est d'ailleurs la requête la plus complexe que j'ai eu a faire.

    j'irais donc regarder vos cours dans un premier temps et votre livre par la suite.

    @+

  4. #4
    Membre habitué Avatar de xess91
    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    408
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 408
    Points : 193
    Points
    193
    Par défaut
    Je viens d'effectuer les changements comme indiqué ci-dessus et ça fonctionne parfaitement quant à la sélection des données, il y a juste une chose qui me pose interrogation...

    J'ai une multiplication des lignes de résultat, comme ceci (pas vraiment évident à déployer):

    => Abonemment1 | critère A | Durée 6 mois | promotion spéciale un objet offert
    => Abonemment1 | critère B | Durée 6 mois | promotion spéciale un objet offert
    => Abonemment1 | critère C | Durée 6 mois | promotion spéciale un objet offert

    Il y est bien évident que les valeurs "Abonnement1", "Durée 6mois" et "promotion spéciale un objet offert" sont répété inutilement.

    Un deuxième exemple avec le résultat d'une requête sur un abonnement de deux durée différentes:

    => Abonemment1 | critère A | Durée 3 mois | NULL
    => Abonemment1 | critère A | Durée 6 mois | promotion spéciale un objet offert
    => Abonemment1 | critère B | Durée 3 mois | NULL
    => Abonemment1 | critère B | Durée 6 mois | promotion spéciale un objet offert
    => Abonemment1 | critère C | Durée 3 mois | NULL
    => Abonemment1 | critère C | Durée 6 mois | promotion spéciale un objet offert

    Est-t-il possible d'obtenir un résultat sous cette forme en se basant sur la structure des tables comme présenter ci-dessus juste en améliorant la requête SQL:

    => Abonemment1 | critère A | Durée 3 mois | NULL
    => NULL | critère B | NULL | NULL
    => NULL | critère C | NULL | NULL

    => Abonemment1 | critère A | Durée 6 mois | promotion spéciale un objet offert
    => NULL | critère B | NULL | NULL
    => NULL | critère C | NULL | NULL

    ???

    ou faut-t-il modifier l'organisation des tables pour obtenir un résultat mieux ranger si je peux dire ?

    Pour ne pas laisser d'interrogation sans réponse j'ai une dernière alternative...

    ou alors comment déployer correctement les données de cette façon en partant du principe que le nombre d'options par abonnement est variable, les durées égalements, etc...au moment de la requête en BDD:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    <?php
    $rqt = "ma requête";
    $goRqt = mysql_query($rqt)or die(mysql_error());
    while($readRqt = mysql_fetch_array($goRqt))
         {
         //ici déployer les données
         }
    ?>
    Merci pour votre aide.

    __________________________________________________

    Edit:

    D'ors et déjà en ajoutant "ORDER BY ad.duree_tbl_abo_duree", j'obtiens:

    => Abonemment1 | critère A | Durée 3 mois | null
    => Abonemment1 | critère B | Durée 3 mois | null
    => Abonemment1 | critère C | Durée 3 mois | null
    => Abonemment1 | critère A | Durée 6 mois | promotion spéciale un objet offert
    => Abonemment1 | critère B | Durée 6 mois | promotion spéciale un objet offert
    => Abonemment1 | critère C | Durée 6 mois | promotion spéciale un objet offert

    c'est déjà mieux mais encore l'idéal pour un déploiement aisé dans php des données.

  5. #5
    Membre habitué Avatar de xess91
    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    408
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 408
    Points : 193
    Points
    193
    Par défaut
    Je me demande si je ne vais pas être obligé d'utiliser un système de requête récursive pour appeler ligne par ligne mes données ! La je ne vois vraiment pas comment trier le résultats de mes jointures mise à part avec des filtres "php", ce qui me parait nettement plus pénible à mettre en place qu'une récursivité.

    Qu'en pensez-vous ?

  6. #6
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 879
    Points : 53 057
    Points
    53 057
    Billets dans le blog
    6
    Par défaut
    Il n'y a pas d'ordre dans les lignes retournée par une requête. Tant est si bien que votre demande de NULLification pour les données soit-disant redondnate n'a aucun sens. Car en effet, vous pouvez aussi bien obtenir en final :

    => Abonemment1 | critère A | Durée 3 mois | NULL
    => NULL | critère B | NULL | NULL
    => NULL | critère C | NULL | NULL

    que :

    => NULL | critère B | NULL | NULL
    => Abonemment1 | critère A | Durée 3 mois | NULL
    => NULL | critère C | NULL | NULL

    ou encore :

    => NULL | critère B | NULL | NULL
    => NULL | critère C | NULL | NULL
    => Abonemment1 | critère A | Durée 3 mois | NULL

    Ce qui serait illisible !!!

    Pour cela vous devez modifier votre IHM...

    Vous avez besoin d'exprimer dans un premier composant visuel seulement les données suivantes :

    => Abonemment1 | Durée 3 mois | NULL

    Puis dans un second composant :

    => critère A
    => critère B
    => critère C

    Donc deux requêtes différentes dont l'une est paramétrée par la précédente. Ceci est un problème de conception d'IHM.

    A +

  7. #7
    Membre habitué Avatar de xess91
    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    408
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 408
    Points : 193
    Points
    193
    Par défaut
    Merci beaucoup SQlpro pour votre réponse bien je n'en ai pas vraiment compris le sens pratique, mais plutôt théorique.

    Ne sachant pas ce que voulait dire "IHM" je suis aller voir sur wikipedia :

    voici la déf. pour ceux qui comme moi ne savent pas :

    IHM:

    L'interface homme-machine, interaction humain-machine (IHM) ou interface personne-machine (IPM) définit, les moyens et outils mis en œuvre, afin qu'un humain puisse contrôler et communiquer avec une machine. Les ingénieurs en ce domaine étudient la façon dont les humains interagissent avec les ordinateurs ou entre eux à l'aide d'ordinateurs, ainsi que la façon de concevoir des systèmes qui soient ergonomiques, efficaces, faciles à utiliser ou plus généralement adaptés à leur contexte d'utilisation.
    Clairement il n'y aucun moyen d'évider la multiplication des lignes !?

    Au finale je suis obligé de faire une requête lié au résultat d'une autre requête de cette manière :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    <?php
    $rqt1 = mysql_query("SELECT el1, el2, el3 FROM tbl1")or die(mysql_error());
    while($tab1 = mysql_fetch_array($rqt1))
         {
         $el1 = $tab['el1'];
         $rqt2 = mysql_query("SELECT ele1, ele2, ele3 FROM tbl2 WHERE ele4 = '$el1"")or die(mysql_error());
         }
    ?>
    Ai-je bien compris ?

  8. #8
    Membre habitué Avatar de xess91
    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    408
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 408
    Points : 193
    Points
    193
    Par défaut
    De retour sur ce sujet, j'ai chercher comment organiser au mieux mes tables et j'avoue ne pas voir de solution permettant de régler ce problème de multiplication des lignes.

    Pourriez-vous me conseillez quant à l'organisation du stockage des données citées ci-dessus.

    Merci à tous pour vos réponses.

Discussions similaires

  1. [AC-2010] Requête action sur grosse table avec trigger LONG
    Par guen dans le forum Macros Access
    Réponses: 5
    Dernier message: 09/04/2015, 20h29
  2. Requête SELECT avec jointure sur deux tables
    Par bud64 dans le forum Requêtes
    Réponses: 6
    Dernier message: 01/10/2010, 14h06
  3. Requête sur 2 tables avec critères de jointures particuliers
    Par Randomdev dans le forum Langage SQL
    Réponses: 3
    Dernier message: 20/01/2009, 18h00
  4. Requête SQL avec jointure sur trois tables
    Par pit2121 dans le forum SQL
    Réponses: 0
    Dernier message: 19/05/2008, 20h24
  5. [Requête] Jointure sur deux tables.
    Par Invité dans le forum Langage SQL
    Réponses: 2
    Dernier message: 20/11/2007, 11h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo