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 PostgreSQL Discussion :

Calcul avec plusieurs aggrégats


Sujet :

Requêtes PostgreSQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Invité
    Invité(e)
    Par défaut Calcul avec plusieurs aggrégats
    Bonjour tout le monde

    Je cherche a faire un peu d'analyse de donnees sur mes tables, et je commence a tomber sur des cas assez recurrents qui me posent probleme.

    Admettons que j'ai 3 tables.
    Une table "community" avec 1 colonne "id" et d'autres attributs
    Une table "user", de meme.
    Une table "community_user" qui me modelise la relation ManyToMany entre les deux.

    Si je veux par exemple le nombre de moins de 30 ans par communaute, pas de soucis

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select community_id, count(user_id) from community_user, user where id=user_id and age<30 group by community_id
    Par contre, comment les choses se passent si je veux calculer plusieurs aggregats avec des filtres differents. Disons renvoyer le nombre de moins de 18 ans et de plus de 60 ans dans la meme requete.

    J'avais commence quelque chose avec des clauses select imbriquees dans mon from, mais je me suis vite rendu compte que mon extraction commencait apres que ces select aient ete faits en integralite. Si je rajoute un limit 10 a la fin par exemple, je dois quand meme patienter jusqu'a la fin des select.

    Ainsi,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    select community_id, c1, c2 from
    (select community_id, count(user_id) as "c1" from community_user group by community_id) as "q1",
    (select community_id, count(user_id) as "c2" from community_user, user where id=user_id and age<30 group by community_id) as "q2"
    where q1.community_id=q2.community_id
    semble vraiment inefficace !

    Y a-t'il une meilleure methode pour faire cela ?
    Le SELECT CASE n'est pas satisfaisant, parce que les filtres que je veux appliquer ne sont pas forcement disjoints.
    Les Window Functions (je suis sous Postgresql) m'ont ete recommandees, mais je ne vois pas du tout comment elles peuvent m'aider...
    Les UNION ne me semblent pas tres "propres" dans ce cas, compare aux jointures (mais vu ce que j'y connais...)
    Dernière modification par Domi2 ; 12/08/2012 à 08h23.

  2. #2
    Invité
    Invité(e)
    Par défaut
    Je viens de penser a ca
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SELECT id,
    (SELECT COUNT(id) FROM user, community_user WHERE id=user_id AND community_id=community.id),
    (SELECT COUNT(id) FROM user, community_user WHERE id=user_id AND age<30 AND community_id=community.id)
    FROM community
    Mais je soupconne que c'est aussi lent que mon autre solution... Qu'en pensez-vous ?

  3. #3
    Expert éminent
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 818
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    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 818
    Billets dans le blog
    14
    Par défaut
    Il faut utiliser CASE et additionner ceux qui répondent à la condition au lieu de les compter.

    Au passage, les jointures s'écrivent depuis 20 ans avec l'opérateur JOIN ; il serait temps de s'y mettre !

    Et indente et aère ton code, il sera plus facile à lire et à débugguer.

    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 cu.community_id, 
    	SUM (
    		CASE 
    			WHEN u.age < 30 THEN 1
    			ELSE 0
    		END
    	) AS moins_de_30_ans,
    	SUM (
    		CASE 
    			WHEN u.age > 60 THEN 1
    			ELSE 0
    		END
    	) AS plus_de_60_ans
    FROM community_user cu
    INNER JOIN user u ON u.id = cu.user_id 
    GROUP BY cu.community_id
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole, en retraite... mais toujours Autoentrepreneur à l'occasion.
    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 !

  4. #4
    Invité
    Invité(e)
    Par défaut
    Merci pour la piste. Je vais lancer un test en taille reelle sur mes tables pour voir comment les differentes approches se comportent. A ce rythme la, ca prendra tout le week-end ^^

    En ce qui concerne le WHERE, c'est une mauvaise habitude que j'ai prise de regarder les requetes genererees par mon ORM (SQLAlchemy) qui au lieu de INNER JOIN utilise des WHERE partout.
    Mais effectivement, c'est plus lisible de separer les clauses de filtrage de la jointure, j'en conviens

  5. #5
    Expert éminent
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 818
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    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 818
    Billets dans le blog
    14
    Par défaut
    Ah ces ORM ! Quelle plaie !
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole, en retraite... mais toujours Autoentrepreneur à l'occasion.
    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 !

  6. #6
    Invité
    Invité(e)
    Par défaut
    Etant plutot debutant en SQL, j'etais parti du principe que l'ORM savait un peu mieux que moi ce qu'il faisait.
    Ensuite je me suis rendu compte que le WHERE et INNER JOIN etaient effectivement interpretes de la meme facon par le moteur, donc je croyais que les formulations etaient juste equivalentes. Je ne savais pas qu'une ecriture etait plus recommandee que l'autre.

Discussions similaires

  1. [XL-2010] Formule de calcul avec plusieurs conditions
    Par a.ouguerzam dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 26/05/2015, 19h12
  2. Calculs avec référence dans plusieurs colonnes
    Par sat478 dans le forum Excel
    Réponses: 1
    Dernier message: 24/11/2010, 17h35
  3. Creation d'une requete avec plusieurs aggrégats
    Par Franck_P dans le forum Langage SQL
    Réponses: 6
    Dernier message: 23/06/2008, 22h38
  4. Tester plusieurs calculs avec try-catch
    Par saddamtohmto dans le forum MATLAB
    Réponses: 2
    Dernier message: 09/08/2007, 11h15
  5. Réponses: 4
    Dernier message: 19/05/2006, 23h14

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