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 :

Requete SQL Optimiser Compteur


Sujet :

Langage SQL

  1. #1
    Membre du Club
    Inscrit en
    Juillet 2006
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 47
    Points : 46
    Points
    46
    Par défaut Requete SQL Optimiser Compteur
    Bonjour, voici mon problème

    Je voudrais avoir un compteur calculé en groupant deux colonnes mais je veux avoir le détail pour chaque ligne

    Un exemple semble plus parlant:
    voici ma table :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    id	name	periode		num
    1	test	periode 1	num 1
    2	test	periode 1	num 2
    3	test	periode 2	num 1
    4	test	periode 2	num 3
    avec la requête suivante j'obtiens le résultat qu'il me faut :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    SELECT
      t.name,
      t.periode,
      t.num,
      (SELECT
         COUNT(t1.num)
       FROM test t1
       WHERE t.name = t1.name
           AND t.periode = t1.periode
       GROUP BY t.name, t.periode) AS result
    FROM test t
    Ma question est de savoir s'il y a moyen d'optimiser cette requête ?

  2. #2
    Expert éminent sénior
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 803
    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 803
    Points : 34 074
    Points
    34 074
    Billets dans le blog
    14
    Par défaut
    Même avec l'exemple, j'ai du mal à comprendre !
    Citation Envoyé par tentos Voir le message
    Je voudrais avoir un compteur calculé en groupant deux colonnes mais je veux avoir le détail pour chaque ligne
    La requête ci-dessous va compter le nombre de lignes pour chaque couple (name, periode)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT name, periode, COUNT(*) AS nbre
    FROM test
    GROUP BY name, periode
    Si tu veux le détail de chaque ligne, c'est à dire le num de chaque ligne en plus du couple (name, periode), le GROUP BY devient inutile !

    Si tu veux compter combien il y a de lignes par triplet (name, periode, num), alors voilà :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT name, periode, num, COUNT(*) AS nbre
    FROM test
    GROUP BY name, periode, num
    Si tu veux compter combien il y a de num distincts pour chaque couple (name, periode), alors voilà :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT name, periode, COUNT(DISTINCT num) AS nbre
    FROM test
    GROUP BY name, periode
    Si ce n'est toujours pas ça ben... explique mieux !

  3. #3
    Membre du Club
    Inscrit en
    Juillet 2006
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 47
    Points : 46
    Points
    46
    Par défaut
    Merci pour ta réponse mais je me suis mal exprimé

    voici le résultat que j'attends :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    name	periode		num	Compteur
    test	periode 1	num 1	2
    test	periode 1	num 2	2
    test	periode 2	num 1	2
    test	periode 2	num 3	2
    je veux afficher toutes mes lignes et pour chaque ligne je veux savoir combien de num j'ai pour un même "name" et une même "periode".

  4. #4
    Expert éminent sénior
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 803
    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 803
    Points : 34 074
    Points
    34 074
    Billets dans le blog
    14
    Par défaut
    Alors (vite fait) comme ça probablement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT t.name, t.periode, t.num, tmp.nbre
    FROM test AS t
    INNER JOIN (
      SELECT name, periode, COUNT(DISTINCT num) AS nbre
      FROM test
      GROUP BY name, periode
    ) AS tmp ON t.name = tmp.name AND t.periode = tmp.periode

  5. #5
    Membre du Club
    Inscrit en
    Juillet 2006
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 47
    Points : 46
    Points
    46
    Par défaut
    Parfait ça fonctionne, je vais faire des tests de performance sur les deux requêtes.

  6. #6
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Sr. Specialist Solutions Architect @Databricks
    Inscrit en
    Septembre 2008
    Messages
    8 453
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Sr. Specialist Solutions Architect @Databricks
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 453
    Points : 18 394
    Points
    18 394
    Par défaut
    Si votre SGBD les supporte, l'utilisation d'une fonction de fenêtrage sera nettement plus performant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT name, periode, num,
           count(*) over(partition by name, periode) as Compteur
      FROM test

  7. #7
    Membre du Club
    Inscrit en
    Juillet 2006
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 47
    Points : 46
    Points
    46
    Par défaut
    Je suis sur MySQL 5.0 et il ne me semble pas que cette fonction existe.

  8. #8
    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 !

    Citation Envoyé par Waldar Voir le message
    Si votre SGBD les supporte, l'utilisation d'une fonction de fenêtrage sera nettement plus performant :
    Hmmm Waldar, justement, c'est une question que je me pose beaucoup en ce moment. Sous Oracle du moins, j'ai l'impression qu'il y a des moments où c'est plus efficace de faire GROUP BY + jointure.

    En fait, le WINDOW SORT effectue le tri sur toute la ligne, ce qui est parfois assez lourd.
    En face, le HASH GROUP BY + HASH JOIN peut être pas si mauvais

    Bien sûr, il faudrait des arguments un peu plus quantitatifs et de vrais test... (j'essaie de m'y mettre)

    Ah oui au passage : effectivement, MySQL n'implémente pas les fonctions analytiques jusqu'à présent !

  9. #9
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 65
    Points : 40
    Points
    40
    Par défaut
    Bonjour à tous, désolé de remonter ce post qui commence à dater mais mon problème est similaire :

    moi il me faudrait afficher quelquechose de la sorte :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    name_id        File_ID         NB_DL_Total         NB_DL_File
       1           	   1	               3                   2
       1	           1	               3                   2
       1              2                   3                   1
       2	           1	               2                   1
       2	           3	               2                   1
    J'arrive pas à ajouter le dernier champ NB_DL_File ( le nombre de fois que le fichier x à été DL par le user y ) je n'arrive pas à voir le truk...
    si quelqu'un à une réponse ou un début au moins
    Merci

  10. #10
    Expert éminent sénior
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 803
    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 803
    Points : 34 074
    Points
    34 074
    Billets dans le blog
    14
    Par défaut
    Un truc dans le genre devrait fonctionner :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    SELECT t.name_id, t.File_ID, t1.NB_DL_Total, t2.NB_DL_FILE
    FROM la_table AS t
    INNER JOIN (
      SELECT name_id, COUNT(*) AS NB_DL_Total
      FROM la_table
      GROUP BY name_id
    ) AS t1
    INNER JOIN (
      SELECT name_id, File_ID, COUNT(*) AS NB_DL_File
      FROM la_table
      GROUP BY name_id, File_ID
    ) AS t2
    ORDER BY name_id, File_ID

  11. #11
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 65
    Points : 40
    Points
    40
    Par défaut
    Merci CinePhil, ça fonctionne bien
    Le temps d'exec est un peu long mais bon ...
    Et par quel moyen serait-il possible de regrouper les fichiers identiques téléchargé par un utilisateur ? de façon à ce qu'un nom de fichier n'apparaisse qu'une fois?
    Dans l'exemple donné au-dessus cela reviendrait à regrouper les lignes 1&2 par exemple... pour un affichage plus propre.
    Si vous avez une idée sinon bah tampis c'est déjà bien comme cela
    Merci d'avance à bientot !

  12. #12
    Expert éminent sénior
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 803
    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 803
    Points : 34 074
    Points
    34 074
    Billets dans le blog
    14
    Par défaut
    Citation Envoyé par viktor951 Voir le message
    Le temps d'exec est un peu long mais bon ...
    Fatal, il y a deux sous-requêtes.
    Mais bon, en plus, je viens de me rendre compte que j'ai oublié les conditions de jointure dans ma requête !
    Essaie celle-ci, elle évitera les deux produits cartésiens :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    SELECT t.name_id, t.File_ID, t1.NB_DL_Total, t2.NB_DL_File
    FROM la_table AS t
    INNER JOIN (
      SELECT name_id, COUNT(*) AS NB_DL_Total
      FROM la_table
      GROUP BY name_id
    ) AS t1 ON t1.name_id = t.name_id
    INNER JOIN (
      SELECT name_id, File_ID, COUNT(*) AS NB_DL_File
      FROM la_table
      GROUP BY name_id, File_ID
    ) AS t2 t2.name_id = t.name_id AND t2.File_ID = t.File_ID
    ORDER BY name_id, File_ID
    Et par quel moyen serait-il possible de regrouper les fichiers identiques téléchargé par un utilisateur ? de façon à ce qu'un nom de fichier n'apparaisse qu'une fois?
    Dans l'exemple donné au-dessus cela reviendrait à regrouper les lignes 1&2 par exemple... pour un affichage plus propre.
    Ben ça c'est justement plus simple parce qu'il n'y a plus besoin que d'une sous requête à mon avis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    SELECT t.name_id, t.File_ID, t1.NB_DL_Total, COUNT(*) AS NB_DL_File
    FROM la_table AS t
    INNER JOIN (
      SELECT name_id, COUNT(*) AS NB_DL_Total
      FROM la_table
      GROUP BY name_id
    ) AS t1 ON t1.name_id = t.name_id
    GROUP BY t.name_id, t.File_ID, t1.NB_DL_Total
    ORDER BY name_id, File_ID

  13. #13
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 65
    Points : 40
    Points
    40
    Par défaut
    Re,
    Les jointures je les avais faites avec un WHERE, à la fin de la requête (EDIT : Et d'ailleurs je n'y arrive pas avec le 'ON' il ne reconnait pas la colonne) ... Est ce très différent? d'un point de vue temps d'exec toujours notamment?
    Sinon la dernière est beaucoup mieux plus rapide et plus clair que demande le peuple
    Pourrais tu m'expliquer le principe du COUNT ? lorsque l'on fait un GROUP BY, cela ne concerne que la colonne COUNT ?
    Merci en tout cas, la dernière requête marche parfaitement,
    A bientôt !

  14. #14
    Expert éminent sénior
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 803
    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 803
    Points : 34 074
    Points
    34 074
    Billets dans le blog
    14
    Par défaut
    Citation Envoyé par viktor951 Voir le message
    Re,
    Les jointures je les avais faites avec un WHERE, à la fin de la requête
    Syntaxe obsolète depuis 1992 !
    (EDIT : Et d'ailleurs je n'y arrive pas avec le 'ON' il ne reconnait pas la colonne)
    Quelle colonne ?
    Je m'aperçois que dans ma seconde version de la première requête, il manque le ON dans la seconde jointure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    AS t2 ON t2.name_id = t.name_id AND t2.File_ID = t.File_ID
    ... Est ce très différent? d'un point de vue temps d'exec toujours notamment?
    Avec des INNER JOIN en principe non mais avec les jointures externes on peut avoir des surprises. On peut aussi et surtout avoir des bugs dans l'écriture de la requête plus difficiles à résoudre avec la syntaxe obsolète. La nouvelle avec JOIN est beaucoup plus claire et sépare la condition de jointure de la condition de restriction (WHERE).

    Pourrais tu m'expliquer le principe du COUNT ? lorsque l'on fait un GROUP BY, cela ne concerne que la colonne COUNT ?
    GROUP BY sert à dire sur quelles colonnes on regroupe les données pour faire les calculs. Il s'agit de toutes les colonnes qui ne font justement pas l'objet d'un calcul regroupé (MIN, MAX, AVG, SUM, COUNT) dans le SELECT.

    COUNT (*) signifie : "Compte toutes les lignes".
    COUNT (une_colonne) : "Compte toutes les lignes où une_colonne a une valeur".
    COUNT (DISTINCT une_colonne) : "Compte combien il y a de valeurs distinctes dans la colonne".

  15. #15
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 65
    Points : 40
    Points
    40
    Par défaut
    Merci de ta réponse sa s'éclaircit un peu dans ma tête
    La colonne qu'il reconnait pas c'est la t.name_id...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SELECT t.name_id, t.File_ID, t1.NB_DL_Total, COUNT(*) AS NB_DL_File
    FROM la_table AS t
    INNER JOIN (
      SELECT name_id, COUNT(*) AS NB_DL_Total
      FROM la_table
      GROUP BY name_id
    ) AS t1 ON t1.name_id = t.name_id
    GROUP BY t.name_id, t.File_ID, t1.NB_DL_Total
    ORDER BY name_id, File_ID
    Alors que avec le WHERE à la fin (sans rien changer, juste copier/coller à la ligne en dessous) cela fonctionne...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    SELECT t.name_id, t.File_ID, t1.NB_DL_Total, COUNT(*) AS NB_DL_File
    FROM la_table AS t
    INNER JOIN (
      SELECT name_id, COUNT(*) AS NB_DL_Total
      FROM la_table
      GROUP BY name_id
    ) AS t1
    WHERE t1.name_id = t.name_id
    GROUP BY t.name_id, t.File_ID, t1.NB_DL_Total
    ORDER BY name_id, File_ID
    Enfin voilà, ne t'embête pas plus, cela fonctionne bien
    je te remercie encore pour ton aide
    à bientôt !

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

Discussions similaires

  1. Requete SQL - Optimisation function avec nombreux parametres
    Par Gallinette59 dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 26/12/2008, 00h55
  2. Optimisation de requete SQL
    Par dark_vidor dans le forum Requêtes
    Réponses: 12
    Dernier message: 15/01/2006, 21h40
  3. Optimiser une Requetes SQL sous ASP
    Par NeHuS dans le forum ASP
    Réponses: 8
    Dernier message: 18/04/2005, 17h26
  4. [PL/SQL] Optimisation requete SQL
    Par CDRIK dans le forum Langage SQL
    Réponses: 3
    Dernier message: 14/10/2004, 10h52
  5. Optimisation requetes SQL
    Par joel90 dans le forum Administration
    Réponses: 18
    Dernier message: 15/05/2004, 22h45

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