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 :

Problème de requête


Sujet :

Langage SQL

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2012
    Messages : 42
    Points : 25
    Points
    25
    Par défaut Problème de requête
    Bonjour,

    j'ai une table commerce qui relie 2 tables, la table commentaires et la table vote:

    et j'aimerai faire une requête qui affiche tous les commerces avec le nombre de commentaires qu'ils ont ainsi que le nombre de vote.

    J'ai donc essayé une requête de telle façon :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    select commerce. *
    , COUNT( commentaires.id )
    , COUNT( vote.id )
      from commerce
    left outer
      join commentaires
        on commentaires.id_commerce = commerce.id
    left outer
      join vote
        on vote.id_commerce = commerce.id
    et là il m'affiche qu'un seul résultat avec le count total des commentaires et vote et non juste le count lié à ce résultat , de + les 2 counts ont 2 résultats en trop oO

    j'ai alors essayé comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    select commerce. *
    , COUNT( commentaires.id )
    , COUNT( vote.id )
      from commerce
    left outer
      join commentaires
        on commentaires.id_commerce = commerce.id
    left outer
      join vote
        on vote.id_commerce = commerce.id
    GROUP BY commerce.id
    ça m'affiche bien tous les commerces avec les counts qui leur sont liés MAIS y a toujours le problème des 2 résultats en trop dans les counts,dans 2 entrées, mon commerce portant l'id 16 qui ne contient que 1 commentaires mais 3 votes, il m'affiche un count de 3 pour les 2, pareil pour mon commerce à l'id 18 il n'a que 1 vote et 3 commentaires, mais il m'affiche 3 pour les 2, pour tous les autres commerce je n'ai aucun soucis, quelqu'un à une idée d'ou pourrait provenir le problème ? :s
    merci d'avance pour vos réponses

  2. #2
    Membre émérite Avatar de pacmann
    Homme Profil pro
    Consulté Oracle
    Inscrit en
    Juin 2004
    Messages
    1 626
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consulté Oracle
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 626
    Points : 2 845
    Points
    2 845
    Par défaut
    Salut,

    Quand tu fais cette requête, tu prends une ligne pour chaque commentaire.
    Puis pour chaque commentaire, tu affiches une ligne pour chaque vote.
    En gros, tu multiplies tes lignes.
    ... il faut donc faire le comptage séparément :
    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
     
    SELECT * 
    FROM 
      (SELECT commerce.id
      , COUNT( commentaires.id )nbc
        FROM commerce
      LEFT OUTER
        JOIN commentaires
          ON commentaires.id_commerce = commerce.id
      GROUP BY commerce.id) c
        JOIN     
      (SELECT commerce.id
      , COUNT( vote.id ) nbv
        FROM commerce
      LEFT OUTER
        JOIN vote
          ON vote.id_commerce = commerce.id
      GROUP BY commerce.id) v ON c.id = v.id

    (c'est ma photo)
    Paku, Paku !
    Pour les jeunes incultes : non, je ne suis pas un pokémon...

    Le pacblog : http://pacmann.over-blog.com/

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2012
    Messages : 42
    Points : 25
    Points
    25
    Par défaut
    ta requête fonctionne bien, mais n'affiche que l'id du commerce, j'ai essayé de remplacer les SELECT commerce.id par un SELECT.*, mais il m'affiche toutes les informations 2* :s

    et puisque là on sépare les requêtes en 2 est-ce qu'on ne pourrait pas mettre un left join au lieu du left outer join ?

    merci encore pour tes réponses

    et si j'ai bien compris tu lies d'abord commentaires et commerce, puis tu lies vote et commerce, puis tu lies les 2 liaisons c'est ça ?

  4. #4
    Membre émérite Avatar de pacmann
    Homme Profil pro
    Consulté Oracle
    Inscrit en
    Juin 2004
    Messages
    1 626
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consulté Oracle
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 626
    Points : 2 845
    Points
    2 845
    Par défaut
    Re,

    LEFT OUTER JOIN et LEFT JOIN sont équivalents.
    Si tu veux plus de colonnes de la table commerce, tu peux les ajouter dans le SELECT et le GROUP BY de la première requête par exemple (ça ne sert à rien de le mettre dans les deux, vu que c'est à priori là même chose)

    [EDIT]
    Oui c'est tout à fait ça, il faut compter séparément. Si tu as N commentaires et M votes ou N et M sont différents de zéro, tes deux count vont retourner N X M !
    Car les count(chose) retournent le nombre de lignes dans le groupe où chose est non NULL...
    Pour cela, on ne joint pas à une même table deux tables de cardinalités différentes et strictement supérieur à 1.

    (c'est ma photo)
    Paku, Paku !
    Pour les jeunes incultes : non, je ne suis pas un pokémon...

    Le pacblog : http://pacmann.over-blog.com/

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2012
    Messages : 42
    Points : 25
    Points
    25
    Par défaut
    j'ai essayé comme ça

    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 * 
    FROM 
      (SELECT commerce.*
      , COUNT( commentaires.id )nbc
        FROM commerce
      LEFT OUTER
        JOIN commentaires
          ON commentaires.id_commerce = commerce.id
      GROUP BY commerce.id) c
        JOIN     
      (SELECT COUNT( vote.id ) nbv
        FROM commerce
      LEFT OUTER
        JOIN vote
          ON vote.id_commerce = commerce.id
    ) v ON c.id = v.id
    mais il me dit qu'il ne connait pas v.id

  6. #6
    Membre émérite Avatar de pacmann
    Homme Profil pro
    Consulté Oracle
    Inscrit en
    Juin 2004
    Messages
    1 626
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consulté Oracle
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 626
    Points : 2 845
    Points
    2 845
    Par défaut
    Il faut que tu laisses le GROUP BY, sinon il ne sait pas comment calculer.

    Tu n'as sencémenta pas le droit, même si ton SGBD te laisse faire, de mettre dans un SELECT des colonnes non agrégées qui ne sont pas présentes dans ton GROUP BY.

    Par ailleurs, il ne faudrait pas utiliser les '*' mais nommer toutes les colonnes...

    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
     
    SELECT * 
    FROM 
      (SELECT commerce.id, col2, col3, ...
      , COUNT( commentaires.id )nbc
        FROM commerce
      LEFT OUTER
        JOIN commentaires
          ON commentaires.id_commerce = commerce.id
      GROUP BY commerce.id, col2, col3, ...) c
        JOIN     
      (SELECT commerce.id, COUNT( vote.id ) nbv
        FROM commerce
      LEFT OUTER
        JOIN vote
          ON vote.id_commerce = commerce.id
      GROUP BY commerce.id
    ) v ON c.id = v.id

    (c'est ma photo)
    Paku, Paku !
    Pour les jeunes incultes : non, je ne suis pas un pokémon...

    Le pacblog : http://pacmann.over-blog.com/

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 198
    Points : 12 774
    Points
    12 774
    Par défaut
    Bonjour,
    C'est normal, la sous-requête v ne renvoie qu'une colonne nbv:
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    ...
    SELECT COUNT( vote.id ) nbv
        FROM commerce
      LEFT OUTER
        JOIN vote
          ON vote.id_commerce = commerce.id
    ) v
    ...
    Donc la table résultante n'a qu'une seule colonne: nbv.

    Tatayo.

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2012
    Messages : 42
    Points : 25
    Points
    25
    Par défaut
    ah ok je pensais que y avait un moyen de tout afficher sans devoir écrire toutes les colonnes :'( mais bon tant pis je vais faire avec ^^ merci beaucoup vous m'avez beaucoup aidé

  9. #9
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2012
    Messages : 42
    Points : 25
    Points
    25
    Par défaut
    désolé je vais encore vous embêter un peu :s

    pacman j'ai fait comme tu as dit, mais la le souçis c'est que j'ai l'id commerce en double, et je ne peux pas enlever le commerce.id d'un des deux select sinon il y a une erreur
    c'est bon j'ai trouvé tout seul

    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
    SELECT c.id, c.id_user, c.nom, c.description, c.image, c.rue, c.num, c.ville, c.cp, c.site, c.tel, c.email, nbc, nbv
    FROM (
     
    SELECT commerce.id, commerce.id_user, commerce.nom, commerce.description, commerce.image, commerce.rue, commerce.num, commerce.ville, commerce.cp, commerce.site, commerce.tel, commerce.email, COUNT( commentaires.id ) nbc
    FROM commerce
    LEFT OUTER 
    JOIN commentaires ON commentaires.id_commerce = commerce.id
    GROUP BY commerce.id_user, commerce.nom, commerce.description, commerce.image, commerce.rue, commerce.num, commerce.ville, commerce.cp, commerce.site, commerce.tel, commerce.email
    )c
    JOIN (
     
    SELECT commerce.id, COUNT( vote.id ) nbv
    FROM commerce
    LEFT OUTER 
    JOIN vote ON vote.id_commerce = commerce.id
    GROUP BY commerce.id
    )v ON c.id = v.id
    mais est-ce que je ne peux pas le simplifier en :

    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
    SELECT c.id, c.id_user, c.nom, c.description, c.image, c.rue, c.num, c.ville, c.cp, c.site, c.tel, c.email, nbc, nbv
    FROM (
     
    SELECT commerce . * , COUNT( commentaires.id ) nbc
    FROM commerce
    LEFT OUTER 
    JOIN commentaires ON commentaires.id_commerce = commerce.id
    GROUP BY commerce.id
    )c
    JOIN (
     
    SELECT commerce.id, COUNT( vote.id ) nbv
    FROM commerce
    LEFT OUTER 
    JOIN vote ON vote.id_commerce = commerce.id
    GROUP BY commerce.id
    )v ON c.id = v.id
    ? :s

  10. #10
    Membre émérite Avatar de pacmann
    Homme Profil pro
    Consulté Oracle
    Inscrit en
    Juin 2004
    Messages
    1 626
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consulté Oracle
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 626
    Points : 2 845
    Points
    2 845
    Par défaut
    C'est très bien, dans le select, tu mets ce que tu veux, préfixé par la table ou la sous-requête d'origine, et non * !

    Maintenant, pour continuer sur la lancer, il faut aussi supprimer l'* de ta sous requête.

    Soit tu ajoutes les colonnes dans dans le GROUP BY :
    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 c.id, c.id_user, c.nom, c.description, c.image, c.rue, c.num, c.ville, c.cp, c.site, c.tel, c.email, nbc, nbv
    FROM (
        SELECT co.id, co.id_user, co.nom, co.description, co.image, co.rue, co.num, co.ville, co.cp, co.site, co.tel, co.email, COUNT( commentaires.id ) nbc
        FROM commerce co
        LEFT OUTER 
        JOIN commentaires ON commentaires.id_commerce = commerce.id
        GROUP BY co.id, co.id_user, co.nom, co.description, co.image, co.rue, co.num, co.ville, co.cp, co.site, co.tel, co.email
        )c
    JOIN ( 
        SELECT commerce.id, COUNT( vote.id ) nbv
        FROM commerce
        LEFT OUTER 
        JOIN vote ON vote.id_commerce = commerce.id
        GROUP BY commerce.id
        )v ON c.id = v.id;
    Sois tu les prends les max des colonnes :
    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
    SELECT c.id, c.id_user, c.nom, c.description, c.image, c.rue, c.num, c.ville, c.cp, c.site, c.tel, c.email, nbc, nbv
    FROM (
        SELECT co.id, max(co.id_user)id_user, max(co.nom)nom, max(co.description)description, max(co.image)image, max(co.rue)rue, max(co.num)num, max(co.ville)ville, max(co.cp) cp, max(co.site) site, max(co.tel) tel, max(co.email) email, COUNT( commentaires.id ) nbc
        FROM commerce co
        LEFT OUTER 
        JOIN commentaires ON commentaires.id_commerce = commerce.id
        GROUP BY co.id
        )c
    JOIN ( 
        SELECT commerce.id, COUNT( vote.id ) nbv
        FROM commerce
        LEFT OUTER 
        JOIN vote ON vote.id_commerce = commerce.id
        GROUP BY commerce.id
        )v ON c.id = v.id
    En soi, quand tu fais un GROUP BY, tu ne peux avoir dans le SELECT que les colonnes du GROUP BY ou des données aggrégées... sinon la question qui se pose est "quelle valeur prend ton dans les lignes de détail pour reporter sur le groupe" ?
    Même si ici en l'occurence, elles ont toute la même valeur, puisque le grouppement ce fait sur la PK de la table commerce...

    (c'est ma photo)
    Paku, Paku !
    Pour les jeunes incultes : non, je ne suis pas un pokémon...

    Le pacblog : http://pacmann.over-blog.com/

  11. #11
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Bonjour,

    Il me semble que vous pouviez tout simplement ajouter un DISTINCT dans vos COUNT, ça éviterait les sous requetes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    SELECT commerce. *
    , COUNT(DISTINCT  commentaires.id )
    , COUNT( DISTINCT vote.id )
      FROM commerce
    LEFT OUTER
      JOIN commentaires
        ON commentaires.id_commerce = commerce.id
    LEFT OUTER
      JOIN vote
        ON vote.id_commerce = commerce.id

  12. #12
    Membre émérite Avatar de pacmann
    Homme Profil pro
    Consulté Oracle
    Inscrit en
    Juin 2004
    Messages
    1 626
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consulté Oracle
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 626
    Points : 2 845
    Points
    2 845
    Par défaut
    Aïe, en terme de performances, ça peut être catastrophique de faire une telle jointure : c'est presque un produit cartésien entre les commentaires et les votes qui ne sont pas liés entre eux...

    (c'est ma photo)
    Paku, Paku !
    Pour les jeunes incultes : non, je ne suis pas un pokémon...

    Le pacblog : http://pacmann.over-blog.com/

Discussions similaires

  1. Réponses: 19
    Dernier message: 27/08/2003, 15h32
  2. problème de requête avec jointures
    Par tinhat dans le forum Requêtes
    Réponses: 7
    Dernier message: 11/08/2003, 10h33
  3. Problème de requètes concurentes
    Par Emmanuel.G dans le forum XMLRAD
    Réponses: 3
    Dernier message: 08/08/2003, 16h51
  4. Réponses: 2
    Dernier message: 16/07/2003, 14h40
  5. Problème dans requête avec count()
    Par BadFox dans le forum Requêtes
    Réponses: 3
    Dernier message: 08/07/2003, 18h02

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