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

Requêtes MySQL Discussion :

pb jointure 4 tables


Sujet :

Requêtes MySQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    107
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations forums :
    Inscription : Avril 2006
    Messages : 107
    Par défaut pb jointure 4 tables
    Bonjour,

    voila je tourne en rond depuis 2 jours sur un pb de jointures liant 4 tables. Tout va bien tant que je lui demande pas d'afficher un certain type de données.

    voici ce que j'obtiens en visuel :

    +----------+---------------+-----------------+-------+-----+------+----------+-------------+-------------+
    | ID stock | libelle pack | libelle produit | sérial | etat | Actif | ID cmd | stock_cmd | ID contenu |
    +----------+---------------+-----------------+-------+-----+------+----------+-------------+-------------+
    | 19 | | Alim R | | eC | 1 | 7 | 19 | 19 |
    -----------------------------------------------------------------------------------------------------------------
    | 12 | pack+alim | R 128Mo |0-012 | eC | 1 | 7 | 20 | 20 |
    -----------------------------------------------------------------------------------------------------------------
    | 18 | pack+alim | Alim R | | eC | 1 | 7 | 20 | 20 |
    -----------------------------------------------------------------------------------------------------------------
    | 58 | | Boitier |0-001 | R | 0 | 12 | 27 | 27 |
    -----------------------------------------------------------------------------------------------------------------
    | 59 | | Boitier |0-002 | eC | 1 | 12 | 27 | 27 |
    -----------------------------------------------------------------------------------------------------------------
    | 60 | 1er ss pack | R 512Mo |0-019 | eC | 1 | 12 | 28 | 28 |
    -----------------------------------------------------------------------------------------------------------------
    | 34 | 1er ss pack | Alim R | | eC | 1 | 12 | 28 | 28 |
    -----------------------------------------------------------------------------------------------------------------
    | 57 | 1er ss pack | R 512Mo | 0-006 | R | 0 | 12 | 28 | 28 |
    +----------+---------------+-----------------+-------+-----+------+----------+-------------+-------------+
    avec la requete suivante :

    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
    SELECT 
                        stock_historique.actif, stock_historique.stock_id, stock_historique.stock_cmd,
                        stock.etat, stock.sn, stock.stock_id,
                        produit.nom as libelle,
                        commande_contenu.*,
                        commande.id_client, commande.id_commande, commande.type,
                        pack_sous_pack.nom
                        FROM stock_historique
                        INNER JOIN stock USING(stock_id)
                        INNER JOIN produit USING(produit_id)
                        INNER JOIN commande_contenu USING(stock_cmd)
                        LEFT JOIN pack_sous_pack ON pack_sous_pack_id = sous_pack_id
                        INNER JOIN commande ON commande_contenu.commande_id = commande.id_commande
                        WHERE commande.id_client='004617'
                        GROUP BY stock.stock_id
                        ORDER BY stock_historique.stock_cmd ASC
    Hors je devrais obtenir ceci :
    +----------+---------------+-----------------+-------+-----+------+----------+-------------+-------------+
    | ID stock | libelle pack | libelle produit | sérial | etat | Actif | ID cmd | stock_cmd | ID contenu |
    +----------+---------------+-----------------+-------+-----+------+----------+-------------+-------------+
    | 19 | | Alim R | | eC | 1 | 7 | 19 | 19 |
    -----------------------------------------------------------------------------------------------------------------
    | 12 | pack+alim | R 128Mo |0-012 | eC | 1 | 7 | 20 | 20 |
    -----------------------------------------------------------------------------------------------------------------
    | 18 | pack+alim | Alim R | | eC | 1 | 7 | 20 | 20 |
    -----------------------------------------------------------------------------------------------------------------
    | 58 | | Boitier |0-001 | R | 0 | 12 | 27 | 27 |
    -----------------------------------------------------------------------------------------------------------------
    | 59 | | Boitier |0-002 | eC | 1 | 13 | 27 | 29 |
    -----------------------------------------------------------------------------------------------------------------
    | 60 | 1er ss pack | R 512Mo |0-019 | eC | 1 | 14 | 28 | 30 |
    -----------------------------------------------------------------------------------------------------------------
    | 34 | 1er ss pack | Alim R | | eC | 1 | 12 | 28 | 28 |
    -----------------------------------------------------------------------------------------------------------------
    | 57 | 1er ss pack | R 512Mo | 0-006 | R | 0 | 12 | 28 | 28 |
    +----------+---------------+-----------------+-------+-----+------+----------+-------------+-------------+
    Je ne dis pas que le résultat que j'obtiens n'est pas logique, il l'est vu que j'ai des produits dans des packs et qu'à la jointure apparemment il ne fait plus cette différence et donne un numéro d'id contenu à tout produit appartenant au pack ciblé.

    J'ai beau faire la requete dans un sens comme dans l'autre c'est à dire partir de la table commande -> table stock historique (ce qui là n'est plus logique), le problème reste le même, l'affichage cafouille quand je lui demande les informations contenues dans la table commande_contenu... hors ce sont les informations les plus importantes
    je ne sais plus quoi faire
    si quelqu'un a une idée je suis preneuse.
    merci par avance.

  2. #2
    Membre Expert
    Avatar de Maljuna Kris
    Homme Profil pro
    Retraité
    Inscrit en
    Novembre 2005
    Messages
    2 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 73
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 613
    Par défaut
    Saluton,
    Ta jointure ne se fait pas entre 4 mais 6 tables, et le GROUP BY risque de ne rien arranger.
    Kie lumo eksistas ankaŭ ombro troviĝas. L.L. Zamenhof
    articles : Comment émuler un tableau croisé [quasi] dynamique
    et : Une énigme mathématique résolue avec MySQL
    recommande l'utilisation de PDO (PHP5 Data Objects)

  3. #3
    Expert éminent
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 818
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 818
    Billets dans le blog
    14
    Par défaut
    Pourquoi faire un GROUP BY alors qu'il n'y a pas de fonction d'agrégation dans ton SELECT ?

    USING empêche de savoir quelles tables sont jointes. Avec quelle table est jointe la table produit ? Avec quelle table est jointe la table commande_contenu ?

    Dans le LEFT JOIN, tu n'as pas indiqué à quelle table appartient la colonne sous_pack_id.

    Pour toutes ces raisons, ta requête est un peu difficile à analyser car on voit mal l'enchaînement des jointures.

    Pour une meilleure lecture, je te conseille aussi d'utiliser des alias.

    Et tant qu'à faire, évite la guerre des étoiles !

    C'est peut-être trop tard mais un id_client en chaîne de caractères, c'est pas top ! Il vaudrait mieux un identifiant entier auto-incrémenté.

    Voici ta requête partiellement récrite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    SELECT sh.actif, sh.stock_id, sh.stock_cmd,
        s.etat, s.sn, s.stock_id,
        cc.*,
        c.id_client, c.id_commande, c.type,
        psp.nom
    FROM stock_historique AS sh
    INNER JOIN stock AS s ON s.stock_id = sh.stock_id
    INNER JOIN produit AS p USING(produit_id)
    INNER JOIN commande_contenu AS cc USING(stock_cmd)
        INNER JOIN commande AS c ON cc.commande_id = c.id_commande
    LEFT JOIN pack_sous_pack AS psp ON psp.pack_sous_pack_id = sous_pack_id
    WHERE c.id_client = '004617'
    ORDER BY sh.stock_cmd
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole, en retraite... mais toujours Autoentrepreneur à l'occasion.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    107
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations forums :
    Inscription : Avril 2006
    Messages : 107
    Par défaut
    Pourquoi faire un GROUP BY alors qu'il n'y a pas de fonction d'agrégation dans ton SELECT ?

    USING empêche de savoir quelles tables sont jointes. Avec quelle table est jointe la table produit ? Avec quelle table est jointe la table commande_contenu ?

    Dans le LEFT JOIN, tu n'as pas indiqué à quelle table appartient la colonne sous_pack_id.

    Pour toutes ces raisons, ta requête est un peu difficile à analyser car on voit mal l'enchaînement des jointures.

    Pour une meilleure lecture, je te conseille aussi d'utiliser des alias.

    Et tant qu'à faire, évite la guerre des étoiles !

    C'est peut-être trop tard mais un id_client en chaîne de caractères, c'est pas top ! Il vaudrait mieux un identifiant entier auto-incrémenté.
    j'ai changé un peu mon code, je te donne la suite en php pour que tu comprennes ^^
    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
    	function getPacksClient($id_client){
    		$query = "SELECT
    					commande_contenu.stock_cmd, commande_contenu.commande_id, commande_contenu.commande_contenu_id, commande_contenu.stock_cmd,
    					produit.nom,
    					stock_historique.actif,
    					stock.stock_id, stock.produit_id,  stock.sn, stock.etat,
    					commande.id_client
    					FROM stock_historique
    					INNER JOIN stock USING(stock_id)
    					INNER JOIN produit USING(produit_id)
    					INNER JOIN commande_contenu ON stock_historique.stock_cmd = commande_contenu.stock_cmd
    					LEFT JOIN commande ON commande.id_commande = commande_contenu.commande_id
    					WHERE commande.id_client = :id_client AND commande_contenu.pack_id IS NOT NULL
    					GROUP BY stock.stock_id
    					ORDER BY stock_historique.stock_cmd ASC
    				"; // :id_client
    		$stmt = PdoSql::getInstance()->prepare($query);
    		$stmt->bindParam(':id_client', $id_client);
    		$stmt->execute();
    		$rowspacks = $stmt->fetchAll(PDO::FETCH_ASSOC | PDO::FETCH_GROUP);
    		return $rowspacks;
    	}
    si je ne fais pas de group by le résultat n'est pas le même.
    Je n'ai pas mis d'alias parce que je ne suis pas la seule à utiliser ce code et donc respect pour ceux qui travaille avec moi.. et je n'ai pas mon mot à dire vu que je ne suis que stagiaire

    pour les sous_pack_id, je n'ai pas mis le nom de colonne tout simplement parce que dans toute ma base il n'y a qu'une seule correspondance.

    l'id client vient d'un annuaire ldap, je ne vais pas m'amuser à critiquer le travail de l'administrateur réseau qui l'a mis en place mais ça tu pouvais pas le savoir ^^

    mais bon en gros, j'ai changé ma requête, elle servait à la base à afficher des produits par numéro de pack (stock_cmd) que je ressort en tableau grace aux 2 fetch.
    J'ai triché via un if sur php pour ne pas afficher les produits seuls et vice versa.
    ça ne résout en aucun cas ma requête sql mais on va dire que c'est une solution d'appoint moins prise de tête :p

  5. #5
    Expert éminent
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 818
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 818
    Billets dans le blog
    14
    Par défaut
    j'ai changé un peu mon code, je te donne la suite en php pour que tu comprennes ^^
    Mais comme il y a toujours des USING, les jointures ne sont toujours pas très explicites !
    J'imagine bien que la première jointure concerne stock_historique et stock mais produit est-elle reliée à stock_historique ou à stock ? Le contenu du SELECT laisse à penser que c'est avec stock.

    si je ne fais pas de group by le résultat n'est pas le même.
    Peut-être même qu'avec ce GROUP BY, tu n'auras pas deux fois le même résultat avec la même requête !
    MySQL est trop permissif sur la syntaxe du GROUP BY. Comme tu fais un GROUP BY seulement sur stock.stock_id, seules les colonnes directement dépendantes de stock_id, c'est à dire celles de la table stock resteront invariables. Pour toutes les autres, MySQL affichera la première valeur qu'il trouve obéissant à la jointure avec la table stock !
    La raison est que les colonnes du SELECT ne faisant pas l'objet d'une fonction de regroupement (SUM, AVG, MIN, MAX, COUNT) doivent toutes figurer dans le GROUP BY. Un autre SGBD aurait rejeté ta requête !

    Je n'ai pas mis d'alias parce que je ne suis pas la seule à utiliser ce code et donc respect pour ceux qui travaille avec moi.. et je n'ai pas mon mot à dire vu que je ne suis que stagiaire
    Un stagiaire qui améliore le code existant, ça ferait plutôt bon effet chez moi mais bon... Et j'aurais tendance à dire qu'améliorer la lecture des requêtes est une marque de respect pour ceux qui auront à la lire !

    Il y a deux fois commande_contenu.stock_cmd dans ton SELECT ! Avec les alias, peut-être que tu l'aurais vu !

    pour les sous_pack_id, je n'ai pas mis le nom de colonne tout simplement parce que dans toute ma base il n'y a qu'une seule correspondance.
    Toi, tu le sais. Les autres développeurs le savent-ils ? Le futur stagiaire ou salarié qui reviendra sur l'appli le saura t-il où aura t-il besoin de le demander aux collègues ?
    Encore une fois, en supprimant l'ambiguïté, on rend la requête plus lisible et compréhensive et on évite de potentielles erreurs. Et tu vois que pour t'aider dans le cadre de ce forum, ça ne facilite pas les choses !

    l'id client vient d'un annuaire ldap, je ne vais pas m'amuser à critiquer le travail de l'administrateur réseau qui l'a mis en place mais ça tu pouvais pas le savoir ^^
    L'administrateur réseau n'est pas en cause mais celui qui a créé la base de données oui !
    L'identifiant LDAP est une chose, l'identifiant dans la table de la BDD en est une autre. L'identifiant LDAP être un attribut significatif et doté d'une contrainte d'unicité mais est une mauvaise clé pour une table dans un SGBDR. Dans mon précédent message, je t'ai mis le lien vers l'article qui explique les avantages de l'identifiant anonyme et auto-incrémenté par rapport à un identifiant signifiant et alpha-numérique.

    afficher des produits par numéro de pack (stock_cmd)
    Tu dis que le numéro de pack est stock_cmd mais il y a aussi un commande_contenu.pack_id !

    Il reste difficile de t'aider à simplifier cette requête mais en tout cas, supprime ce GROUP BY qui est probablement la source de l'erreur dans le résultat que tu affiches dans ton premier message !

    La structure des tables pourrait aider à la compréhension.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole, en retraite... mais toujours Autoentrepreneur à l'occasion.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

Discussions similaires

  1. Jointure de table avec Interbase
    Par ada_b dans le forum InterBase
    Réponses: 21
    Dernier message: 12/05/2010, 19h52
  2. Réponses: 7
    Dernier message: 10/02/2005, 00h13
  3. [FB1.5]Vue avec jointure sur tables ?
    Par Sitting Bull dans le forum SQL
    Réponses: 2
    Dernier message: 07/12/2004, 17h07
  4. jointure sur table et procedure stocké
    Par pram dans le forum SQL
    Réponses: 3
    Dernier message: 18/11/2004, 21h56
  5. requete(jointure 2 tables) qui marche pas
    Par DaxTaz dans le forum Langage SQL
    Réponses: 3
    Dernier message: 01/06/2004, 17h50

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