简体   繁体   English

计算Postgres中的百分比

[英]Calculating Percentages in Postgres

I'm completely new to PostgreSQL. 我是PostgreSQL的新手。 I have the following table called my_table: 我有一个名为my_table的下表:

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

I want to calculate the percentage of 'good' from column c for each date. 我想为每个日期计算出c列中“良好”的百分比。 I know how to get the number of 'good': 我知道如何获得“好”的数字:

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

That returns: 返回:

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

My goal is to get this: 我的目标是得到这个:

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

So I tried the following: 所以我尝试了以下方法:

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;

And I get an error saying 我说一个错误

more than one row returned by a subquery used as an expression. 子查询返回的多于一行用作表达式。

I found this answer but not sure how to or if it applies to my case: 我找到了这个答案,但不确定如何或是否适用于我的情况:

Calculating percentage in PostgreSql 在PostgreSQL中计算百分比

How do I go about calculating the percentage for multiple rows? 如何计算多行的百分比?

avg() is convenient for this purpose: avg()可以方便地实现此目的:

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

How does this work? 这是如何运作的? c = 'good' is a boolean expression. c = 'good'是一个布尔表达式。 The ::int converts it to a number, with 1 for true and 0 for false. ::int将其转换为数字,其中1表示true,0表示false。 The average is then the average of a bunch of 1s and 0s -- and is the ratio of the true values. 那么平均值就是一串1和0的平均值-是真实值的比率。

You could use a conditional sum for get the good value and count for total 您可以使用条件和来获得良好的价值,并计算总数

below an exaustive code sample 精美代码示例下方

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

and for your result 为了你的结果

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

or as suggested by a_horse_with_no_name using count(*) filter() 或如a_horse_with_no_name所建议使用count(*)filter()

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

For this case you need to use conditional AVG() : 对于这种情况,您需要使用条件AVG()

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

See the demo . 参见演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM