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 :

Group By et jointure


Sujet :

Requêtes MySQL

  1. #1
    Invité
    Invité(e)
    Par défaut Group By et jointure
    Bonjour,

    J'ai un petit souci avec MySQL.

    Quelqu'un pourrait-il m'expliquer la différence entre ces deux requêtes ? En effet, elles ne me retournent pas le même résultat et je ne comprends pas pourquoi.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    SELECT a.nom AS nom, 
    a.prenom AS prenom, 
    b.age AS age, 
    c.domicile AS domicile,
    v.voiture_name AS nomVoiture,
    count(*) AS count
    FROM personne a
    JOIN info b ON a.id = b.id_personne
    JOIN maison c ON a.id = c.id_personne
    JOIN voiture v ON a.id = v.id_conducteur
     
    GROUP BY nom, prenom, age, domicile, nomVoiture;


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    SELECT tmp.nom, tmp.prenom, tmp.age, tmp.domicile, tmp.nomVoiture
    count(*) AS count FROM
     
    (SELECT a.nom AS nom, 
    a.prenom AS prenom, 
    b.age AS age, 
    c.domicile AS domicile,
    v.voiture_name AS nomVoiture,
    FROM personne a
    JOIN info b ON a.id = b.id_personne
    JOIN maison c ON a.id = c.id_personne
    JOIN voiture v ON a.id = v.id_conducteur) tmp
     
    GROUP BY tmp.nom, tmp.prenom, tmp.age, tmp.domicile, tmp.nomVoiture;
    Les tables ont été change pour plus de clarté. J'en ai peut-être laisse passer une, mais dans les requêtes originales, il n'y a pas d'erreurs de typo.

    Si j'enlève le GROUP BY de la première requête, je retrouve le bon résultat. Sachant aussi après enquête que le GROUP BY du premier me fait disparaitre des enregistrements alors qu'il n'y a pas lieu d'être.

    Merci d'avance !
    Oodzee.
    Dernière modification par Invité ; 05/08/2013 à 15h10. Motif: ajout de precisions

  2. #2
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 947
    Points : 5 846
    Points
    5 846
    Par défaut
    La 2eme requête est fausse, il y a une opération de regroupement mais pas d’agrégation dans la sous-requête.
    Dans ce genre de cas mysql prend des valeurs au hasard pour répondre à la requête fausse...
    Le GROUP BY placé en dehors de la sous-requête correspond en fait à un DISTINCT.

    A lire sur le sujet :
    http://cedric-duprez.developpez.com/...r-group-by/#L3

    Si vous supprimer le GROUP BY de la 1ere requête, la requête devient incohérente...

  3. #3
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par skuatamad Voir le message
    La 2eme requête est fausse, il y a une opération de regroupement mais pas d’agrégation dans la sous-requête.
    Dans ce genre de cas mysql prend des valeurs au hasard pour répondre à la requête fausse...
    Le GROUP BY placé en dehors de la sous-requête correspond en fait à un DISTINCT.

    A lire sur le sujet :
    http://cedric-duprez.developpez.com/...r-group-by/#L3

    Si vous supprimer le GROUP BY de la 1ere requête, la requête devient incohérente...
    Merci pour la reponse et pour le lien !

    Je me douterais bien que j'arriverais a foirer la "simplification" de ma requête. Le COUNT est a placer a l'extérieur de la deuxieme sous-requête.

    Quant a enlever le GROUP BY de la premiere requête, je veux dire que si je l'enleve ainsi que le COUNT(*), j'obtiens le bon nombre de lignes.

    Pour résumer :

    * Premiere requête, sans GROUP BY : 6000 lignes environ (que des enregistrements uniques)
    * Premiere requête, avec GROUP BY : 4000 lignes environ (alors qu'il ne devrait pas y avoir de regroupements possibles)

    * Deuxieme requête, avec GROUP BY : 6000 lignes environ

  4. #4
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 947
    Points : 5 846
    Points
    5 846
    Par défaut
    Ok je comprends, je pense que c'est à cause des relations personne/info, personne/maison et personne/voiture qui sont probablement 1..n.
    Comme il n'y a pas de lien entre info maison et voiture, ça génère une sorte de produit cartésien.

    Regarde cet exemple (développé sous oracle mais ça ne change rien, pour info tout le début avec WITH permet de simuler les 3 tables) :
    http://www.developpez.net/forums/d12...e/#post6958167

  5. #5
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par skuatamad Voir le message
    Ok je comprends, je pense que c'est à cause des relations personne/info, personne/maison et personne/voiture qui sont probablement 1..n.
    Comme il n'y a pas de lien entre info maison et voiture, ça génère une sorte de produit cartésien.

    Regarde cet exemple (développé sous oracle mais ça ne change rien, pour info tout le début avec WITH permet de simuler les 3 tables) :
    http://www.developpez.net/forums/d12...e/#post6958167
    Je viens de verifier et malheureusement, il s'agit de relation 1-1...

  6. #6
    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 : 60
    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 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Ou bien je suis rouillé, ou bien il n'y a pas d'erreur dans les deux requêtes !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    SELECT a.nom AS nom, 
    a.prenom AS prenom, 
    b.age AS age, 
    c.domicile AS domicile,
    v.voiture_name AS nomVoiture,
    count(*) AS count
    FROM personne a
    JOIN info b ON a.id = b.id_personne
    JOIN maison c ON a.id = c.id_personne
    JOIN voiture v ON a.id = v.id_conducteur
     
    GROUP BY nom, prenom, age, domicile, nomVoiture;
    Cette requête compte le nombre de lignes pour chaque ensemble {nom, prenom, age, domicile, nomVoiture} différent.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    SELECT tmp.nom, tmp.prenom, tmp.age, tmp.domicile, tmp.nomVoiture
    count(*) AS count FROM
     
    (SELECT a.nom AS nom, 
    a.prenom AS prenom, 
    b.age AS age, 
    c.domicile AS domicile,
    v.voiture_name AS nomVoiture,
    FROM personne a
    JOIN info b ON a.id = b.id_personne
    JOIN maison c ON a.id = c.id_personne
    JOIN voiture v ON a.id = v.id_conducteur) tmp
     
    GROUP BY tmp.nom, tmp.prenom, tmp.age, tmp.domicile, tmp.nomVoiture;
    Cette requête semble faire la même chose, en compliquant avec une sous-requête.

    Que cherchez-vous à obtenir ?
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    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 !

  7. #7
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    Ou bien je suis rouillé, ou bien il n'y a pas d'erreur dans les deux requêtes !

    Que cherchez-vous à obtenir ?
    Je cherche a comprendre pourquoi la premiere requête retourne un résultat différent de la seconde. Sachant que le résultat attendu est celui de la seconde, mais que, comme vous l'avez signalé, cette requête complique inutilement l'écriture.

  8. #8
    Invité
    Invité(e)
    Par défaut
    Je ne sais pas si ca rejoint la relation 1-n évoquée précédemment, mais je pense avoir une piste

    a.id, b.id_personne, c.id_personne et v.id_conducteur sont bels et bien des clés pour chaque table. Cependant, concernant la table voiture, il y a plusieurs lignes de voiture qui contiennent le meme nom de voiture. Etant donne que ce nom se retrouve dans la clause GROUP BY, peut-être que les mauvais résultats viennent de la.

  9. #9
    Invité
    Invité(e)
    Par défaut
    Ok, je crois qu'il est temps d'être un peu plus précis.

    Voici a l'heure actuelle la requête qui pose problème:

    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
    SELECT 
        MONTH(ach.date),
        MONTH(ven.date),
        v.numSerie,
        v.modele,
        b.adresse,
        a.age,
        a.numSecuSociale,
        COUNT(*)
    FROM personne a
    JOIN maison b ON a.d_maison  = b.id
    JOIN achat ach ON a.d_date_achat = ach.id
    JOIN voiture v ON a.d_voiture = v.id
    JOIN vente ven ON a.d_date_vente = ven.id
     
    WHERE ach.date >= @start_date
      AND ven.date >= ach.date 
      AND ven.date <= @end_date
      AND v.numSerie IN (463,960,1047,1050,1051,1052)
    GROUP BY MONTH(ach.date), MONTH(ven.date), v.numSerie, v.modele, b.adresse, a.age, a.numSecuSociale;
    J'ai juste remplace les noms des tables et des champs parce que ca compliquerait plus qu'autre chose, mais tout le reste est identique. A savoir que :
    • @end_date et @start_date ont été défini auparavant et ne sont pas la cause du problème
    • Les numéros de sécurité social sont tous distincts
    • Les jointures se font en 1-1


    Si j'enlève le GROUP BY et le COUNT(*), j'obtiens 6000 lignes. Les numéros de sécurité social étant tous différent dans la bd, le GROUP BY ne devrait avoir aucun effet. Pourtant en l'utilisant, on obtient 4000 lignes. Ce nombre correspond également au nombre de lignes qui ont le numSerie = 463.

    J'espère que c'est plus clair et que l'un d'entre vous aura une piste !

    Merci encore.

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

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


    La bonne piste a déjà été donnée par skuatamad.

    Et vu que vous ne posez pas de question je ne vois pas bien ce que l'on pourrait répondre.

  11. #11
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par punkoff Voir le message
    bonjour,


    La bonne piste a déjà été donnée par skuatamad.

    Et vu que vous ne posez pas de question je ne vois pas bien ce que l'on pourrait répondre.
    J'avais effectivement oublie une question :

    "Si j'enlève le GROUP BY et le COUNT(*), j'obtiens 6000 lignes. Les numéros de sécurité social étant tous différent dans la bd, le GROUP BY ne devrait avoir aucun effet. Pourtant en l'utilisant, on obtient 4000 lignes. Ce nombre correspond également au nombre de lignes qui ont le numSerie = 463."

    Ma question est donc : "Pourquoi cette incoherence ?"

    Quant a la piste de skuatamad, elle est bonne certes, mais elle ne s'applique pas ici. Tous les champs de la table "a" qui sont des cles vers les tables "b", "ach", "v" et "ven" font le lien avec UNE seule ligne pour chacune de ces tables.

  12. #12
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 947
    Points : 5 846
    Points
    5 846
    Par défaut
    Commencez par la requête suivante qui normalement ne renverra aucune ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    select a.numSecuSociale,
           COUNT(*)
      from personne a
     group by a.numSecuSociale
    having count(*) > 1
    Puis rajoutez au fur et à mesure vos jointures et voyez quelle table génère plusieurs numSecuSociale dans le résultat de la requête.
    Les numéros de sécurité social étant tous différent dans la bd
    Fsmrel dirait que c'est l'inconvénient du Sorry Query Language, qui renvoie un sac à partir d'une relation au lieu de renvoyer une relation et qui a donc introduit le mot clé DISTINCT pour contourner cet inconvénient, par exemple :
    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
    SQL> with t as (
      2  select 1 as c from dual
      3  ),
      4  t2 as (
      5  select 1 as c, 1 as c2 from dual union all
      6  select 1 as c, 2 as c2 from dual
      7  )
      8  select t.c
      9    from t
     10    join t2 on t2.c = t.c;
     
             C
    ----------
             1
             1
     
    SQL>

  13. #13
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par skuatamad Voir le message
    Commencez par la requête suivante qui normalement ne renverra aucune ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    select a.numSecuSociale,
           COUNT(*)
      from personne a
     group by a.numSecuSociale
    having count(*) > 1
    Puis rajoutez au fur et à mesure vos jointures et voyez quelle table génère plusieurs numSecuSociale dans le résultat de la requête.
    Le hic, c'est que cette requête ne renverra jamais aucune ligne. Je me rends compte que je ne l'ai pas précisé, mais sans le GROUP BY, il y a 6000 lignes, et avec, il y en a 4000 mais la valeur de COUNT(*) pour chacune d'entre elles est de 1.

    Merci encore pour l'aide !

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Citation Envoyé par Oodzee Voir le message
    Le hic, c'est que cette requête ne renverra jamais aucune ligne. Je me rends compte que je ne l'ai pas précisé, mais sans le GROUP BY, il y a 6000 lignes, et avec, il y en a 4000 mais la valeur de COUNT(*) pour chacune d'entre elles est de 1.

    Merci encore pour l'aide !
    c'est pas possible.

    la requete de Skuatamad renverra forcément des lignes quand vous aurez rajoutez les jointures.

    Sinon on ne passerai pas de 4K a 6k de lignes.

  15. #15
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par punkoff Voir le message
    c'est pas possible.

    la requete de Skuatamad renverra forcément des lignes quand vous aurez rajoutez les jointures.

    Sinon on ne passerai pas de 4K a 6k de lignes.
    C'est bien le fond du problème. C'est totalement incohérent, mais c'est ce qui se passe.
    Les 4000 lignes correspondent au nombre de lignes qui ont le numSerie 463, meme si le résultat inclut des lignes avec un numSerie différent (classique de MySQL lorsqu'il fait des select sur des champs qui ne sont pas dans le GROUP BY, ce qui n'est pas censé etre le cas ici). Du coup, si le GROUP BY est fait seulement pour les lignes qui ont un numSerie de 463, le compte du GROUP BY est logique. Ce qui l'est moins, c'est pourquoi les autres ne sont plus la.

    D'ailleurs, si j'enlève le 463, les résultats concordent avec ou sans GROUP BY (ce qui est le résultat attendu).

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    si dans votre requete vous rajoutez au niveau du select (et du group by) l'id de la personne que se passe-t-il ?

  17. #17
    Invité
    Invité(e)
    Par défaut
    Apres plusieurs tests, il semblerait que le problème soit plutot au niveau de la base de données que de la requête...

    A l'heure actuelle, j'utilise Brighthouse. J'ai effectué une copie des tables en questions (copie quasi-forme, a l'exception d'une table dont une partie du contenu n'a pu être copie car trop de données) mais en utilisant MyISAM, aucun problème. J'ai effectué une copie de ces nouvelles tables en réutilisant Brighthouse, aucun problème.

    J'avance dans la résolution du problème, mais j'ai l'impression d'être toujours aussi loin...

    Quelqu'un qui aurait déja vu ce problème ou un problème similaire et qui pourrait m'aiguiller ? Ne serait-ce qu'un terme pour designer ce problème (bd corrompue ou inconsistence des données peut-être ?).

  18. #18
    Invité
    Invité(e)
    Par défaut
    Mise a jour : le probleme semble arriver aux alentours des 4093/4099 lignes. Avant, la requete semble fonctionner correctement, apres non. Ce qui me fait dire que le probleme survient a la suite de la ligne 4096, vu que c'est un chiffre rond.

    Peut-etre une des variables qui cause probleme...

    Les 3 variables qui ont une valeur de 4096 sont :

    query_cache_min_res_unit
    range_alloc_block_size
    transaction_prealloc_size

    Work in progress... et toujours a l'affut de vos remarques si vous en avez

  19. #19
    Invité
    Invité(e)
    Par défaut
    Problème resolu. Il s'agissait d'un bug lié à Brighthouse. Et malgré que mon probleme correspondait bien a celui qu'il connaissait, ils n'ont pas jugé bon d'en parler et preferé me laisser rechercher pendant des semaines la solution a ce probleme insoluble jusqu'a la sortie du patch (qui a resolu ce probleme).

    Merci encore a tous ceux qui ont essayé de m'aider

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

Discussions similaires

  1. Linq Group Vu et Jointure
    Par mdordenart dans le forum Linq
    Réponses: 0
    Dernier message: 22/08/2012, 14h22
  2. GROUP BY et JOINTURE
    Par wehtam dans le forum Requêtes
    Réponses: 8
    Dernier message: 18/10/2010, 15h46
  3. GROUP BY et JOINTURE ?
    Par ebaynaud dans le forum Langage SQL
    Réponses: 2
    Dernier message: 28/04/2009, 15h28
  4. [Oracle 9i] GROUP BY avec jointure.
    Par requinc dans le forum Langage SQL
    Réponses: 3
    Dernier message: 27/04/2006, 12h29
  5. Groupe By avec jointure
    Par batoubat dans le forum Langage SQL
    Réponses: 4
    Dernier message: 27/12/2005, 14h12

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