2
votes

Calcul des pourcentages dans Postgres

Je suis complètement nouveau dans PostgreSQL. J'ai le tableau suivant appelé my_table:

SELECT date, 
       (SELECT COUNT(c) 
        FROM my_table 
        WHERE c != 'bad' 
        GROUP BY date) / COUNT(c) * 100 as perc_good 
FROM my_table 
GROUP BY date;

Je veux calculer le pourcentage de «bon» de la colonne c pour chaque date. Je sais comment obtenir le nombre de "bons":

date         perc_good
2019-05-02   25
2019-05-01   75

Cela renvoie:

count    date
3        2019-05-02
1        2019-05-01

Mon objectif est d'obtenir ceci:

SELECT COUNT(c), date FROM my_table WHERE c != 'bad' GROUP BY date;

J'ai donc essayé ce qui suit:

a    b    c        date
1    0    good     2019-05-02
0    1    good     2019-05-02
1    1    bad      2019-05-02
1    1    good     2019-05-02
1    0    bad      2019-05-01
0    1    good     2019-05-01
1    1    bad      2019-05-01
0    0    bad      2019-05-01

Et j'obtiens une erreur disant

plus d'une ligne renvoyée par une sous-requête utilisée comme expression.

J'ai trouvé cette réponse mais je ne sais pas comment ou si elle s'applique à mon cas:

Calcul du pourcentage dans PostgreSql

Comment calculer le pourcentage pour plusieurs lignes?


0 commentaires

3 Réponses :


1
votes

Vous pouvez utiliser une somme conditionnelle pour obtenir la bonne valeur et compter pour le total

sous un exemple de code explicatif

select  date
  , ((count(*) filter(where c='good'))/count(*))* 100 perc_good
from my_table
group by  date 

et pour votre résultat

XXX

ou comme suggéré par a_horse_with_no_name en utilisant count (*) filter ()

  select  date
    , (sum(case when c='good' then 1 else 0 end) / count(c))* 100 perc_good
  from my_table
  group by  date 


4 commentaires

Dans Postgres, vous pouvez simplifier les expressions CASE par ex. filtre count (*) (où c = 'bon')


@a_horse_with_no_name .. correct. C'est mon habitude d'utiliser CASE


@Abelisto: qui utilise toujours la division entière, vous aurez besoin de (...) :: numeric / count (*) pour éviter cela


@a_horse_with_no_name Oui sûrement. Mais en arithmétique entière x * 100 / y généralement plus précis que x / y * 100 En fait, dans cette réponse, le résultat sera toujours 0 : < code> sélectionnez 99/100 * 100, 99 * 100/100;



3
votes

avg () est pratique à cet effet:

select date,
       avg( (c = 'good')::int ) * 100 as percent_good
from t
group by date
order by date;

Comment ça marche? c = 'good' est une expression booléenne. Le :: int le convertit en un nombre, avec 1 pour vrai et 0 pour faux. La moyenne est alors la moyenne d'un groupe de 1 et de 0 - et est le rapport des valeurs vraies.


0 commentaires

1
votes

Dans ce cas, vous devez utiliser AVG () :

SELECT 
  date, 
  100 * avg(case when c = 'good' then 1 else 0 end) perc_good 
FROM my_table 
GROUP BY date;

Voir le démo .


0 commentaires