Précédent   Forum des professionnels en informatique > Bases de données > MySQL > Requêtes
Requêtes Forum d'entraide sur les requêtes MySQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 17/11/2010, 12h26   #1
Membre à l'essai
 
Inscription : avril 2006
Messages : 87
Détails du profil
Informations personnelles :
Âge : 36
Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

Informations forums :
Inscription : avril 2006
Messages : 87
Points : 20
Points : 20
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 :

Citation:
+----------+---------------+-----------------+-------+-----+------+----------+-------------+-------------+
| 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 :
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 :
Citation:
+----------+---------------+-----------------+-------+-----+------+----------+-------------+-------------+
| 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.
Riwalenn est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/11/2010, 14h28   #2
Expert Confirmé
 
Avatar de Maljuna Kris
 
Homme Avcxjo MoKo
Retraité
Inscription : novembre 2005
Messages : 2 527
Détails du profil
Informations personnelles :
Nom : Homme Avcxjo MoKo
Âge : 60

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

Informations forums :
Inscription : novembre 2005
Messages : 2 527
Points : 3 515
Points : 3 515
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)
Maljuna Kris est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/11/2010, 14h42   #3
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur d'études en informatique
Inscription : août 2006
Messages : 10 927
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
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 : 10 927
Points : 18 115
Points : 18 115
Envoyer un message via MSN à CinePhil
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 :
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 de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« 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 Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/11/2010, 18h41   #4
Membre à l'essai
 
Inscription : avril 2006
Messages : 87
Détails du profil
Informations personnelles :
Âge : 36
Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

Informations forums :
Inscription : avril 2006
Messages : 87
Points : 20
Points : 20
Citation:
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 :
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
Riwalenn est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/11/2010, 09h51   #5
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur d'études en informatique
Inscription : août 2006
Messages : 10 927
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
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 : 10 927
Points : 18 115
Points : 18 115
Envoyer un message via MSN à CinePhil
Citation:
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.

Citation:
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 !

Citation:
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 !

Citation:
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 !

Citation:
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.

Citation:
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 de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« 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 Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 17h08.


 
 
 
 
Partenaires

Hébergement Web