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 :

Simplifier requêtes avec jointures


Sujet :

Langage SQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 22
    Par défaut Simplifier requêtes avec jointures
    Bonjour à tous,

    Je tâtonne avec l'utilisation des jointures.

    Et aujourd'hui je cherche à simplifier deux requêtes que j'utilise.

    Voilà mon cas :

    - J'ai une table "articles"
    - une table "categories"
    - une table "catart" (qui lie les articles aux catégories - un article peut appartenir à plusieurs catégories : deux colonnes : idcat | idart)

    Je dois sortir un listing d'articles avec différents champs, notamment toutes les catégories dans lesquelles l'article apparait.
    J'ai plusieurs types dans ma table categories :

    - marques (idcat=10)
    - accessoires (idcat=12)
    - telephones (idcat=11)

    Pour compliquer l'affaire, ma catégorie "telephones" est elle même liée à la catégorie "marques" : Exemple: un téléphone "N86" est de marque "Nokia" (dans ma table le "N86" a donc pour "idcat" = 11 et pour "idcat2" = 10)

    Et moi je dois sortir :

    Article1 | Batterie | Nokia | N86
    Article1 | Batterie | HTC | Legend
    Article2 | Coque | Samsung | Galaxy SII
    etc.

    A l'heure actuelle j'utilise donc deux requêtes sans doute archaïques, mais qui ont le mérite de fonctionner... mais qui me prennent un max de ressources et de temps d'exécution.

    Je fais donc d'abord :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT A.id, A.denom as ARTICLE, B.denom as TELEPHONE, D.denom as MARQUE
    FROM afs_article A 
    LEFT JOIN afs_catart C ON A.id=C.idart 
    LEFT JOIN afs_categorie B ON B.id=C.idcat 
    LEFT JOIN afs_categorie D ON B.idcat2=D.id
    WHERE B.idcat=11
    ORDER BY ARTICLE
    Mais je dois encore aller chercher ma catégorie "accessoires", et c'est pour elle que je butte... Donc pour le moment j'ai cette solution - de bourrin - de lancer ma boucle sur ma première requête, et d'aller pour chaque ligne chercher le type d'accessoires d'appartenance :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT K.id as ACCESSOIRES 
    FROM afs_catart J 
    LEFT JOIN afs_categorie K ON K.id=J.idcat 
    WHERE J.idart=$IDARTICLE AND K.idcat=12
    Et donc ma question est évidemment : comment faire ça en une seule requête.

    J'espère que j'ai été assez clair et pas trop long !

    Merci d'avance pour toute aide !

  2. #2
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Par défaut
    bonjour,

    Il faut remonter votre condition dans la clause where, sinon vous allez forcer des jointures internes.


    Essayez ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    SELECT A.id, A.denom as ARTICLE, B.denom as TELEPHONE, D.denom as MARQUE, e.denom as accessoire
    FROM afs_article A 
    LEFT JOIN afs_catart C ON A.id=C.idart 
    LEFT JOIN afs_categorie B ON B.id=C.idcat and  B.idcat=11 
    LEFT JOIN afs_categorie D ON B.idcat2=D.id
    left outer join afs_categorie e on e.id = c.idcat and e.idcat = 12
    ORDER BY ARTICLE
    Concernant les perf, cette requête ramène beacoup d'enregistrement ?
    Pour la table afs_catart je déduis que la primary key est le couple {idart, idcat} ?
    Est-ce que votre colonne idcat2 de la table afs_categorie est indéxé ?

  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
    Dans ta première requête, tu fais des jointures externes mais tu mets une condition dans le WHERE qui porte sur une table externe, transformant ainsi la jointure externe en jointure interne.

    Lire mon billet de blog pour plus d'explications.

    Par contre j'ai du mal à comprendre ton besoin et à deviner la structure de tes tables au vu de la requête.

    Tu peux fournir ce qui manque pour qu'on puisse t'aider plus efficacement ?
    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 averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 22
    Par défaut
    La vache vous êtes rapide à répondre ! C'est moi qui suis à la bourre du coup !

    Donc pour ta requête punkoff, ça me donne une liste trop longue (130 articles au lieu de 125 000), avec pas mal de champs NULL :

    ID | Article | Telephone | Marque | Accessoire
    1000 	Bluetooth Mono sans fil HTC 	NULL 	NULL 	NULL
    1000 	Bluetooth Mono sans fil HTC 	NULL 	NULL 	NULL
    1000 	Bluetooth Mono sans fil HTC 	NULL 	NULL 	Bluetooth
    1000 	Bluetooth Mono sans fil HTC 	NULL 	NULL 	NULL
    1000 	Bluetooth Mono sans fil HTC 	NULL 	NULL 	NULL
    1000 	Bluetooth Mono sans fil HTC 	NULL 	NULL 	NULL
    1000 	Bluetooth Mono sans fil HTC 	NULL 	NULL 	NULL
    1000 	Bluetooth Mono sans fil HTC 	Z6 	MOTOROLA 	NULL
    1000 	Bluetooth Mono sans fil HTC 	Z3 	MOTOROLA 	NULL
    "Bluetooth Mono sans fil HTC" c'est le nom de l'article.
    Et surtout je n'ai jamais à la fois le téléphone, la marque et l'accessoire sur la même ligne.

    Oui c'est bien le couple id_art/id_cat le primary key sur afs_catart, et ma colonne idcat2 sur afs_categorie n'est pas indexée...

  5. #5
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Par défaut
    fournissez un jeu de donnée test + résutlat attendu + structure comme le suggère CinePhil

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 22
    Par défaut
    Citation Envoyé par punkoff Voir le message
    fournissez un jeu de donnée test + résutlat attendu + structure comme le suggère CinePhil
    Les quelques lignes que j'ai donné ci-dessus suffisent ou non ?
    Pour les structures de tables, vous avez besoin de quoi d'autre ?

    Pour le résultat attendu, et bien ce serait ça :

    id ARTICLE TELEPHONE MARQUE ACCESSOIRE
    1000 Bluetooth Mono sans fil HTC T4242 HTC Bluetooth
    1000 Bluetooth Mono sans fil HTC 6280 BLACKBERRY Bluetooth
    1000 Bluetooth Mono sans fil HTC E60 NOKIA Bluetooth
    1000 Bluetooth Mono sans fil HTC L600 SAMSUNG Bluetooth
    (...)
    69 	Adaptateur allume cigare HTC 	P3300 	HTC 	Divers
    69 	Adaptateur allume cigare HTC 	MAX 4G 	HTC 	Divers
    69 	Adaptateur allume cigare HTC 	TYTN II 	HTC 	Divers
    90 	Adaptateur allume cigare Nokia 	6310 	NOKIA 	Divers
    89 	Adaptateur allume cigare Nokia 	X3 	NOKIA 	Divers

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 22
    Par défaut
    Si ça peut simplifier les choses, je n'ai pas forcément besoin du DENOM de la catégorie ACCESSOIRE.
    Je peux récupérer simplement son ID, dans la table afs_catart.

    Mais bon... je sais pas si ça simplifie les choses...

  8. #8
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Par défaut
    Citation Envoyé par bibos Voir le message
    Les quelques lignes que j'ai donné ci-dessus suffisent ou non ?
    Pour les structures de tables, vous avez besoin de quoi d'autre ?

    Non, pas suffisant, car votre résultat est incohérant par rapport à votre présentation.

    Dans votre 1er poste, j'ai simplement repris votre 2eme requête pour la joindre avec votre 1ere requête.

    Donc si la requête que je vous ai posté ne retourne que des valeurs null pour votre accessoire cela veut dire que votre 2eme requête initial ne renvoie rien.

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 22
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    Dans ta première requête, tu fais des jointures externes mais tu mets une condition dans le WHERE qui porte sur une table externe, transformant ainsi la jointure externe en jointure interne.

    Lire mon billet de blog pour plus d'explications.

    Par contre j'ai du mal à comprendre ton besoin et à deviner la structure de tes tables au vu de la requête.

    Tu peux fournir ce qui manque pour qu'on puisse t'aider plus efficacement ?
    Ok donc ma requête revient à faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT A.id, A.denom AS ARTICLE, B.denom AS TELEPHONE, D.denom AS MARQUE
    FROM afs_article A
    LEFT JOIN afs_catart C ON A.id = C.idart
    INNER JOIN afs_categorie B ON B.id = C.idcat AND B.idcat =11
    LEFT JOIN afs_categorie D ON B.idcat2 = D.id
    ORDER BY ARTICLE
    Mais après je bloque toujours...

    J'ai essayé d'ajouter la ligne de punkoff, ce qui me donne le bon nombre de lignes, sans champs NULL... mais avec toujours le même type d'accessoire remonté !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT A.id, A.denom AS ARTICLE, B.denom AS TELEPHONE, D.denom AS MARQUE, E.denom as ACCESSOIRE
    FROM afs_article A
    LEFT JOIN afs_catart C ON A.id = C.idart
    INNER JOIN afs_categorie B ON B.id = C.idcat
    AND B.idcat =11
    LEFT JOIN afs_categorie D ON B.idcat2 = D.id
    LEFT OUTER JOIN afs_categorie E ON E.id = E.idcat AND E.idcat = 12
    ORDER BY ARTICLE
    --------

    id 	ARTICLE 	TELEPHONE 	MARQUE 	ACCESSOIRE
    1000 	Bluetooth Mono sans fil HTC 	Iolite T4242 	HTC 	Bluetooth
    1000 	Bluetooth Mono sans fil HTC 	6280 	BLACKBERRY 	Bluetooth
    1000 	Bluetooth Mono sans fil HTC 	E60 	NOKIA 	Bluetooth
    1000 	Bluetooth Mono sans fil HTC 	L600 	SAMSUNG 	Bluetooth
    Pour plus de détail sur la structure de mes tables :

    afs_article
    ID | DENOM

    afs_catart
    IDCAT | IDART

    afs_categorie
    ID | DENOM | IDCAT | IDCAT2

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 22
    Par défaut
    Citation Envoyé par bibos Voir le message
    J'ai essayé d'ajouter la ligne de punkoff, ce qui me donne le bon nombre de lignes, sans champs NULL... mais avec toujours le même type d'accessoire remonté !

    SELECT A.id, A.denom AS ARTICLE, B.denom AS TELEPHONE, D.denom AS MARQUE, E.denom as ACCESSOIRE
    FROM afs_article A
    LEFT JOIN afs_catart C ON A.id = C.idart
    INNER JOIN afs_categorie B ON B.id = C.idcat
    AND B.idcat =11
    LEFT JOIN afs_categorie D ON B.idcat2 = D.id
    LEFT OUTER JOIN afs_categorie E ON E.id = E.idcat AND E.idcat = 12
    ORDER BY ARTICLE
    Forcément je me suis planté en mettant E.id=E.idcat au lieu de E.id=C.idcat...

    Bref, si je corrige, j'ai des champs null dans la colonne accessoire.

  11. #11
    Membre Expert
    Inscrit en
    Août 2009
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 1 073
    Par défaut
    Citation Envoyé par bibos Voir le message
    A l'heure actuelle j'utilise donc deux requêtes sans doute archaïques, mais qui ont le mérite de fonctionner... mais qui me prennent un max de ressources et de temps d'exécution.
    Un max à quel point ? Avez-vous des index sur les tables ? Les requêtes me semblent correctes, les volumétries sont faibles, ça devrait tourner tout seul si c'est bien indexé.

    EDIT :
    Votre requête ne retourne rien parce que de la table C, vous tentez une jointure simultanée avec deux fois la même table sur la même colonne. Aucune ligne ne peut a priori avoir un idcat qui corresponde à simultanément un id de categorie ayant un idcat de 11 et un autre ayant un idcat de 12. Je me permet d'ailleurs de signaler que le nommage des colonnes prête hautement à confusion !
    Quelque chose du genre (avant de regarder à faire de l'optimisation) vous renvoie-t-il des résultats corrects :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    SELECT A.id, A.denom AS ARTICLE, B.denom AS TELEPHONE, D.denom AS MARQUE, E.denom AS ACCESSOIRE
    FROM afs_article A
    JOIN afs_catart C ON A.id = C.idart
    JOIN afs_categorie B ON B.id = C.idcat AND B.idcat=11
    JOIN afs_categorie D ON B.idcat2 = D.id
    -- là il faut refaire une jointure avec catart
    JOIN afs_catart C2 ON A.id = C2.idart
    JOIN afs_categorie E ON E.id = C2.idcat AND E.idcat=12
    ORDER BY ARTICLE

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 22
    Par défaut
    Citation Envoyé par Rei Ichido Voir le message
    Un max à quel point ? Avez-vous des index sur les tables ? Les requêtes me semblent correctes, les volumétries sont faibles, ça devrait tourner tout seul si c'est bien indexé.
    Ca met environ 140 secondes à s'exécuter quand même...
    Et ça utilise plus de 800Mo de mémoire...

  13. #13
    Membre Expert
    Inscrit en
    Août 2009
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 1 073
    Par défaut
    J'ai édité mon post plus haut pour suggérer une requête.

    Sur la question des perfs, il ya des index ?

  14. #14
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 22
    Par défaut
    Citation Envoyé par Rei Ichido Voir le message
    Votre requête ne retourne rien parce que de la table C, vous tentez une jointure simultanée avec deux fois la même table sur la même colonne. Aucune ligne ne peut a priori avoir un idcat qui corresponde à simultanément un id de categorie ayant un idcat de 11 et un autre ayant un idcat de 12. Je me permet d'ailleurs de signaler que le nommage des colonnes prête hautement à confusion !
    Quelque chose du genre (avant de regarder à faire de l'optimisation) vous renvoie-t-il des résultats corrects :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    SELECT A.id, A.denom AS ARTICLE, B.denom AS TELEPHONE, D.denom AS MARQUE, E.denom AS ACCESSOIRE
    FROM afs_article A
    JOIN afs_catart C ON A.id = C.idart
    JOIN afs_categorie B ON B.id = C.idcat AND B.idcat=11
    JOIN afs_categorie D ON B.idcat2 = D.id
    -- là il faut refaire une jointure avec catart
    JOIN afs_catart C2 ON A.id = C2.idart
    JOIN afs_categorie E ON E.id = C2.idcat AND E.idcat=12
    ORDER BY ARTICLE
    J'ai tout compris, et ça marche impeccable... Il fallait refaire une jointure sur catart!

    Et donc on peut encore optimiser cette requête ?
    Parce que là elle est traitée en 0.0001 sec !

  15. #15
    Membre Expert
    Inscrit en
    Août 2009
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 1 073
    Par défaut
    Vu le temps de réponse, les index doivent être corrects

  16. #16
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 22
    Par défaut
    Bon et bien merci à toi et merci à tout le monde !

    Et la prochaine fois, je commencerai par le début

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Requête avec jointure
    Par Maglight dans le forum Langage SQL
    Réponses: 4
    Dernier message: 17/11/2005, 09h57
  2. optimisation d'une requête avec jointure
    Par champijulie dans le forum PostgreSQL
    Réponses: 8
    Dernier message: 07/07/2005, 09h45
  3. Requête avec jointures
    Par Corben dans le forum Langage SQL
    Réponses: 4
    Dernier message: 16/11/2004, 12h55
  4. Mise à jour de table impossible après requête avec jointure
    Par sto dans le forum Bases de données
    Réponses: 5
    Dernier message: 17/03/2004, 13h24
  5. problème de requête avec jointures
    Par tinhat dans le forum Requêtes
    Réponses: 7
    Dernier message: 11/08/2003, 10h33

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