Précédent   Forum des professionnels en informatique > Bases de données > Langage SQL
Langage SQL Forum d'entraide sur le langage SQL et sur les questions liées à la conception de schéma (DDL). Cours SQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 23/11/2011, 11h42   #1
Invité de passage
 
Inscription : septembre 2007
Messages : 6
Détails du profil
Informations forums :
Inscription : septembre 2007
Messages : 6
Points : 1
Points : 1
Par défaut [MySQL] Effectuer une distribution statistique en SQL

Bonjour,

Je suis confronté à une problématique de "distribution statistique" que j'aimerais résoudre avec une requête SQL.

Je travaille sur des réseaux sociaux, et je souhaite compter le nombre d'amis de chacun de mes utilisateurs.

Ce que je sais faire :
- ramener le nombre d'amis pour chacun de mes utilisateurs
- ramener le nombre d'utilisateurs ayant 1, 2, ... amis
- ramener le nombre total d'utilisateurs ayant des amis

Ce que je souhaite faire :
- ramener le nombre d'amis (en X) et la répartition en % par rapport au total de mes utilisateurs (en Y) => exemple

Ma requête actuelle :
Code :
1
2
3
4
5
6
7
SELECT nb_amis, count(util_id) AS nb_util
FROM (
    SELECT utilisateurs.util_id, count(DISTINCT amis.ami_id) AS nb_amis
    FROM utilisateurs INNER JOIN amis ON utilisateurs.util_id = amis.util_id
    GROUP BY 1
) tab
GROUP BY 1;
Pouvez-vous m'aider ?
Merci par avance ! :o)
loic_cadiot est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 11h54   #2
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur d'études en informatique
Inscription : août 2006
Messages : 11 029
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
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 : 11 029
Points : 18 327
Points : 18 327
Envoyer un message via MSN à CinePhil
Comme ça ?
Code :
1
2
3
4
5
6
7
SELECT nb_amis, (100 * count(util_id) AS nb_util) / (SELECT COUNT(*) FROM utilisateurs) AS pourcentage
FROM (
    SELECT utilisateurs.util_id, count(DISTINCT amis.ami_id) AS nb_amis
    FROM utilisateurs INNER JOIN amis ON utilisateurs.util_id = amis.util_id
    GROUP BY utilisateurs.util_id
) tab
GROUP BY nb_amis
__________________
Philippe Leménager. Ingénieur d'étude à l'École Nationale de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« 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 Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 12h00   #3
Expert Confirmé
 
Homme
Inscription : mai 2002
Messages : 1 646
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations forums :
Inscription : mai 2002
Messages : 1 646
Points : 2 643
Points : 2 643
hmm attention Cinéphil, ceci est une requête scalaire (edit : remarque vu la répartition .... ca ne sera pas un problème)

Il vaudrai mieux prendre une option de jointure cartésiène pour ce problème je pense.

Vu que me MySql ne supporte pas le cross join ..

Code :
1
2
3
4
5
6
7
8
9
 
SELECT nb_amis, (100 * count(util_id) AS nb_util) / max(nb_tot) AS pourcentage
FROM (
    SELECT utilisateurs.util_id, count(DISTINCT amis.ami_id) AS nb_amis
    FROM utilisateurs INNER JOIN amis ON utilisateurs.util_id = amis.util_id
    GROUP BY utilisateurs.util_id
) tab,
(SELECT COUNT(*) AS nb_tot FROM utilisateurs) 
GROUP BY nb_amis
punkoff est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 12h08   #4
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur d'études en informatique
Inscription : août 2006
Messages : 11 029
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
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 : 11 029
Points : 18 327
Points : 18 327
Envoyer un message via MSN à CinePhil
Euh... il me semble avoir répondu à ça :
Citation:
ramener le nombre d'amis et la répartition en % par rapport au total de mes utilisateurs
Le fait que ce soit en X et en Y n'est pas du ressort du SGBD il me semble.

Dans ta requête comme dans la mienne :
Code :
SELECT COUNT(*) AS nb_tot FROM utilisateurs
Ne donne qu'un seul nombre : le nombre de lignes de la table utilisateurs, c'est à dire le nombre total d'utilisateurs.

Demander dans ta requête le max(nb_tot) donnera toujours le même nombre !

J'ai donc l'impression que ta requête donne le même résultat que la mienne mais avec une jointure inutile.
__________________
Philippe Leménager. Ingénieur d'étude à l'École Nationale de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« 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 Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 12h09   #5
Membre Expert
 
Avatar de pacmann
 
Homme Pacman Pacman
Business analyst
Inscription : juin 2004
Messages : 1 417
Détails du profil
Informations personnelles :
Nom : Homme Pacman Pacman
Âge : 31
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Business analyst
Secteur : Finance

Informations forums :
Inscription : juin 2004
Messages : 1 417
Points : 2 309
Points : 2 309
Salut !

D'après ton graphique, tu veux une somme cumulative, donc pour mois il y a deux étapes :
- Grouper le nombre d'utilisateurs par nombre d'amis
- Sommer pour chaque nombre d'amis le pourcentage de gens qui ont autant ou moins.

Sans fonctions analytiques, ça donne un truc du genre :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
SELECT tab4.nb_amis, sum(nb_util) / (SELECT count(*) FROM utilisateurs) pct
FROM 
    (SELECT nb_amis, count(*) AS nb_util
    FROM (
        SELECT count(amis.ami_id) AS nb_amis
        FROM utilisateurs 
            LEFT OUTER JOIN amis ON utilisateurs.util_id = amis.util_id
        GROUP BY utilisateurs.util_id
    ) tab
    GROUP BY nb_amis) tab2
    JOIN
        (SELECT DISTINCT nb_amis
    FROM (
        SELECT count(amis.ami_id) AS nb_amis
        FROM utilisateurs 
            LEFT OUTER JOIN amis ON utilisateurs.util_id = amis.util_id
        GROUP BY utilisateurs.util_id
    ) tab3
    ) tab4
    ON tab4.nb_amis >= tab2.nb_amis
GROUP BY tab4.nb_amis
Punkoff, tu penses que MySQL ré-exécute la requête scalaire à chaque fois ?
(Sur Oracle je parierais que non)
__________________

(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/
pacmann est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 12h29   #6
Membre émérite
 
Homme Olivier Dehorter
Ingenieur de recherche - Ecologue
Inscription : juin 2003
Messages : 698
Détails du profil
Informations personnelles :
Nom : Homme Olivier Dehorter
Localisation : France

Informations professionnelles :
Activité : Ingenieur de recherche - Ecologue

Informations forums :
Inscription : juin 2003
Messages : 698
Points : 839
Points : 839
Pour faire une digression (sur le plan statistique), le terme de distribution statistique est incorrect.

La distribution statistique est le représentation des données sous forme graphique pour vérifier quelle suit une loi statistique (gauss, Poisson, etc) - pour faire simple -
dehorter olivier est actuellement connecté   Envoyer un message privé Réponse avec citation 10
Vieux 23/11/2011, 13h07   #7
Expert Confirmé
 
Homme
Inscription : mai 2002
Messages : 1 646
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations forums :
Inscription : mai 2002
Messages : 1 646
Points : 2 643
Points : 2 643
Citation:
Envoyé par pacmann Voir le message
Punkoff, tu penses que MySQL ré-exécute la requête scalaire à chaque fois ?
(Sur Oracle je parierais que non)
C'est la question que j'essai d'éllucidé en ce moment même
le trip c'est qu'ici il n'y a qu'un "select count(*) from ma_table" sans référence à l'autre table ... du coup ...


edit: je ne peux pas tester sur MySql, mais sur 2 autres sgbd ca passe sasn problème.

Donc je suppose que la solution de Cinephil est mieux (je parle de la technique utilisée pas de la requête à fournir pour résoudre le problème initiale)
punkoff est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 13h39   #8
Membre Expert
 
Avatar de pacmann
 
Homme Pacman Pacman
Business analyst
Inscription : juin 2004
Messages : 1 417
Détails du profil
Informations personnelles :
Nom : Homme Pacman Pacman
Âge : 31
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Business analyst
Secteur : Finance

Informations forums :
Inscription : juin 2004
Messages : 1 417
Points : 2 309
Points : 2 309
Citation:
Envoyé par dehorter olivier Voir le message
Pour faire une digression (sur le plan statistique), le terme de distribution statistique est incorrect.

La distribution statistique est le représentation des données sous forme graphique pour vérifier quelle suit une loi statistique (gauss, Poisson, etc) - pour faire simple -
Ouah, tu chipottes quand même

La répartition d'une population par modalité, et la version cumulative, c'est la version discrète de ce que tu obtiens en intégrant la loi de probabilité...
En tous cas, le terme de distribution s'applique bien ici. Après, c'est le mot statistique que tu n'aimes pas ?
__________________

(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/
pacmann est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 14h25   #9
Membre émérite
 
Homme Olivier Dehorter
Ingenieur de recherche - Ecologue
Inscription : juin 2003
Messages : 698
Détails du profil
Informations personnelles :
Nom : Homme Olivier Dehorter
Localisation : France

Informations professionnelles :
Activité : Ingenieur de recherche - Ecologue

Informations forums :
Inscription : juin 2003
Messages : 698
Points : 839
Points : 839
Citation:
Envoyé par pacmann Voir le message
Ouah, tu chipottes quand même

La répartition d'une population par modalité, et la version cumulative, c'est la version discrète de ce que tu obtiens en intégrant la loi de probabilité...
En tous cas, le terme de distribution s'applique bien ici. Après, c'est le mot statistique que tu n'aimes pas ?
oui, je sais ET tu as raison, la version cumulative est bien une distribution au sens statistique.


Sur le plan SQL, je ne suis pas très au point dessus; mais les CTE pourraient être utile dans ce contexte (si elles sont implémentées dans MySql ?)
dehorter olivier est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 14h55   #10
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur d'études en informatique
Inscription : août 2006
Messages : 11 029
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
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 : 11 029
Points : 18 327
Points : 18 327
Envoyer un message via MSN à CinePhil
Eh non ! Pas de récursif chez MySQL !

Je n'ai pas regardé la requête de Pacman en détail mais j'ai l'impression que ce sera plus rapide de récupérer le paquet de données de ma requête puis de traiter la cumulation dans le langage de programmation en même temps que la construction du graphique.
__________________
Philippe Leménager. Ingénieur d'étude à l'École Nationale de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« 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 Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 23/11/2011, 15h17   #11
Membre Expert
 
Avatar de pacmann
 
Homme Pacman Pacman
Business analyst
Inscription : juin 2004
Messages : 1 417
Détails du profil
Informations personnelles :
Nom : Homme Pacman Pacman
Âge : 31
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Business analyst
Secteur : Finance

Informations forums :
Inscription : juin 2004
Messages : 1 417
Points : 2 309
Points : 2 309
Oui s'il y a des problèmes de perf, c'est sûrement ce qu'il y a de mieux à faire... ou alors passer par une table temporaire (toujours pas aussi rapide qu'un traitement itératif sur le premier résultset, mais une fois l'aggrégat enregistré, la requête doit être beaucoup plus légère).

Olivier, la CTE aurait été utile uniquement sous Oracle, parce qu'elle permet la matérialisation du résultat (c'est à dire la mise en table temporaire "système").

Mais avant de reprocher ça à MySQL, je reprocherais plutôt l'absence de fonctions analytique qui auraient certainement permis d'écrire le résultat très différemment ! (et plus rapidement bien sûr )

Par exemple sous Oracle :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
 
SELECT nb_amis, sum(nb_util) OVER(ORDER BY nb_amis) / count(*) OVER(ORDER BY NULL)
FROM (
       SELECT nb_amis, count(*) nb_util
       FROM (
            SELECT count(b.amis_id) nb_amis
            FROM utilisateurs a
              LEFT OUTER JOIN amis b ON a.util_id = b.util_id
            GROUP BY a.util_id)
            )
       GROUP BY nb_amis
      )
__________________

(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/
pacmann est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 14h37.


 
 
 
 
Partenaires

Hébergement Web