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 :

Requete select sur 2 tables => doublons


Sujet :

Requêtes MySQL

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Points : 19
    Points
    19
    Par défaut Requete select sur 2 tables => doublons
    Bonjour à tous,

    Je débute sur MySql (version 5), et j'ai un pb avec une requete un peu compliquée (pour moi !).

    Voici ma requete :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT tbContacts.IDClient, tbContacts.IDEntreprise, tbContacts.IDContact, tbContacts.Civilite, tbContacts.Nom, tbContacts.Prenom, tbContacts.CodePostal ContCP, tbContacts.Ville ContVille, tbContacts.TelFixePro, tbContacts.TelMobilePro, tbContacts.EmailPro, tbContacts.TelFixePerso, tbContacts.TelMobilePerso, tbContacts.EmailPerso, 
    tbEntreprises.RaisonSociale, tbEntreprises.TelStandard, tbEntreprises.FaxStandard, tbEntreprises.EmailStandard, tbEntreprises.CodePostal EntCP, tbEntreprises.Ville EntVille
    FROM tbContacts,tbEntreprises
    WHERE tbContacts.IDClient=106 AND tbEntreprises.IDClient=106 AND (tbEntreprises.IDEntreprise = tbContacts.IDEntreprise OR tbContacts.IDEntreprise = 0)
    En fait, ça marche, SAUF QUE :

    • si un contact existe mais n'est pas affecté à une entreprise (tbContacts.IDEntreprise = 0), la requete "doublonne" ce contact autant de fois que le nombre d'entreprises retournées !
    • Si j'enlève la clause "OR tbContacts.IDEntreprise = 0" dans la clause WHERE, les contacts non affectés à une entreprise ne sont pas retournés par la requete.
    • J'ai aussi essayé d'ajouter "DISTINCT" aprés le SELECT, mais ça ne change rien !


    Auriez-vous une idée de ce qui coince ?

    Merci d'avance pour votre aide !

  2. #2
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    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 799
    Points : 34 048
    Points
    34 048
    Billets dans le blog
    14
    Par défaut
    • si un contact existe mais n'est pas affecté à une entreprise (tbContacts.IDEntreprise = 0), la requete "doublonne" ce contact autant de fois que le nombre d'entreprises retournées !
    • Si j'enlève la clause "OR tbContacts.IDEntreprise = 0" dans la clause WHERE, les contacts non affectés à une entreprise ne sont pas retournés par la requete.
    Il faut utiliser des jointures normalisées, et notamment la jointure externe...
    http://sqlpro.developpez.com/cours/sqlaz/jointures/

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Points : 19
    Points
    19
    Par défaut
    Merci pour la réponse.
    Je suis allé voir le lien que tu m'as proposé et ai transformé ma requête en suivant les règles de jointure externe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT tbContacts.IDClient, tbContacts.IDEntreprise, tbContacts.IDContact, tbContacts.Civilite, tbContacts.Nom, tbContacts.Prenom, tbContacts.CodePostal ContCP, tbContacts.Ville ContVille, tbContacts.TelFixePro, tbContacts.TelMobilePro, tbContacts.EmailPro, tbContacts.TelFixePerso, tbContacts.TelMobilePerso, tbContacts.EmailPerso, 
    tbEntreprises.RaisonSociale, tbEntreprises.TelStandard, tbEntreprises.FaxStandard, tbEntreprises.EmailStandard, tbEntreprises.CodePostal EntCP, tbEntreprises.Ville EntVille
    FROM tbContacts 
    LEFT OUTER JOIN tbEntreprises ON tbContacts.IDClient = tbEntreprises.IDClient AND tbContacts.IDEntreprise = tbEntreprises.IDEntreprise 
    WHERE tbContacts.IDClient=106 AND tbEntreprises.IDClient=106
    Le pb, c'est que ça ne me renvoie toujours que les contacts affectés à une entreprise, alors que je les veux tous.

    Ou me suis-je trompé ?

  4. #4
    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 : 72
    Localisation : France, Finistère (Bretagne)

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

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 613
    Points : 3 950
    Points
    3 950
    Par défaut
    Citation Envoyé par Lamanne Voir le message
    Le pb, c'est que ça ne me renvoie toujours que les contacts affectés à une entreprise, alors que je les veux tous.

    Ou me suis-je trompé ?
    Si tu laisses ta clause WHERE aussi restrictive
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    WHERE tbContacts.IDClient=106 AND tbEntreprises.IDClient=106
    le résultat restera confiné à cette valeur.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Points : 19
    Points
    19
    Par défaut
    La valeur "106" est là pour simplifier. Cette valeur est paramétrée dans mon code.

    Le problème n'est pas là.

    En terme de structure, j'ai :

    CLIENTS
    => ENTREPRISES
    => CONTACTS
    => CONTACTS SANS ENTREPRISE

    Les contacts dépendant d'une entreprise et les contacts sans entreprise sont dans la même table "tbContacts".

    Pour les contacts sans entreprise, le champ "IDEntreprise" est à 0.

    L'IDClient "106" sert à limiter les réponses aux données du client identifié par "106" pour les besoins du test.

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Points : 19
    Points
    19
    Par défaut Mille pardons
    Mille pardons !

    Vous m'avez mis la puce à l'oreille sur la condition WHERE...

    J'ai supprimé la clause WHERE sur tbEntreprises.IDEntreprise comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT tbContacts.IDClient, tbContacts.IDEntreprise, tbContacts.IDContact, tbContacts.Civilite, tbContacts.Nom, tbContacts.Prenom, tbContacts.CodePostal ContCP, tbContacts.Ville ContVille, tbContacts.TelFixePro, tbContacts.TelMobilePro, tbContacts.EmailPro, tbContacts.TelFixePerso, tbContacts.TelMobilePerso, tbContacts.EmailPerso, 
    tbEntreprises.RaisonSociale, tbEntreprises.TelStandard, tbEntreprises.FaxStandard, tbEntreprises.EmailStandard, tbEntreprises.CodePostal EntCP, tbEntreprises.Ville EntVille
    FROM tbContacts 
    LEFT OUTER JOIN tbEntreprises ON tbContacts.IDClient = tbEntreprises.IDClient AND tbContacts.IDEntreprise = tbEntreprises.IDEntreprise 
    WHERE tbContacts.IDClient=106
    et Oh miracle : ça fonctionne !

    Merci infiniment pour votre aide !

  7. #7
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    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 799
    Points : 34 048
    Points
    34 048
    Billets dans le blog
    14
    Par défaut
    Voici ta requête avec des alias et quelques sauts de ligne supplémentaires pour la rendre plus lisible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    SELECT c.IDClient, c.IDEntreprise,
        c.IDContact, c.Civilite, c.Nom, c.Prenom,
        c.CodePostal ContCP, c.Ville ContVille, 
        c.TelFixePro, c.TelMobilePro, c.EmailPro,
        c.TelFixePerso, c.TelMobilePerso, c.EmailPerso, 
        e.RaisonSociale, 
        e.TelStandard, e.FaxStandard, e.EmailStandard, 
        e.CodePostal EntCP, e.Ville EntVille
    FROM tbContacts c
    LEFT OUTER JOIN tbEntreprises e ON c.IDClient = e.IDClient AND c.IDEntreprise = e.IDEntreprise 
    WHERE c.IDClient=106 AND e.IDClient=106
    Comme la condition de jointure est double avec un AND, les contacts avec IDEntreprise = 0 n'auront pas de correspondance dans la table tbEntreprise et le SGBD mettra NULL sur toutes les colonnes issues de tbEntreprise, y compris e.IDClient, même si c.IDClient existe dans tbEntreprise.

    Comme la restriction supprime toutes les lignes qui n'ont pas e.IDClient = 106, les contacts avec IDClient = 106 mais IDEntreprise = 0 sont éliminés.

    Tu devrais essayer avec un OR dans la double condition de jointure à la place du AND, ou bien ne faire la condition de jointure que sur IDClient.

    EDIT : Argh ! Trop tard !

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Points : 19
    Points
    19
    Par défaut
    Merci CinéPhil !

    Apparemment, j'ai trouvé la solution, mais ce qui m'ennuie, c'est que je ne comprends pas vraiment pourquoi ça fonctionne avec la modif que j'ai indiquée plus tôt !

    Enfin, l'essentiel, c'est que ça fonctionne...

    Mais si tu comprends pourquoi, je suis intéressé par une explication (pas trop technique, si possible !)

  9. #9
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    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 799
    Points : 34 048
    Points
    34 048
    Billets dans le blog
    14
    Par défaut
    Et bien l'explication est dans mon précédent message !
    Ce que j'ai préconisé pour la clause de jointure peut apparemment s'appliquer aussi à la clause de restriction.

    D'ailleurs, je serais curieux de savoir si ma solution fonctionnait aussi ?

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

Discussions similaires

  1. Requete select sur plusieurs tables
    Par cl@ndestIno dans le forum Langage SQL
    Réponses: 3
    Dernier message: 15/12/2008, 12h36
  2. Requete mysql : select sur deux tables
    Par IP-Fix dans le forum Requêtes
    Réponses: 9
    Dernier message: 12/11/2008, 16h03
  3. requete SELECT sur 3 tables
    Par TheBlackReverand dans le forum Langage SQL
    Réponses: 3
    Dernier message: 29/01/2008, 12h53
  4. Requete select sur 2 tables
    Par beho dans le forum Requêtes
    Réponses: 3
    Dernier message: 13/02/2007, 15h19
  5. Requete SELECT SUR +sieurs tables
    Par yanis97 dans le forum Langage SQL
    Réponses: 5
    Dernier message: 21/09/2006, 13h30

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