【问题标题】:Calculating Percentages in Postgres在 Postgres 中计算百分比
【发布时间】:2019-05-29 16:07:32
【问题描述】:

我对 PostgreSQL 完全陌生。我有一个名为 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

我想计算每个日期 c 列中“好”的百分比。我知道如何获得“好”的数量:

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

返回:

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

我的目标是得到这个:

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

所以我尝试了以下方法:

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;

我得到一个错误提示

用作表达式的子查询返回多行。

我找到了这个答案,但不确定如何或是否适用于我的案例:

Calculating percentage in PostgreSql

如何计算多行的百分比?

【问题讨论】:

    标签: sql postgresql group-by


    【解决方案1】:

    avg() 方便用于此目的:

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

    这是如何工作的? c = 'good' 是一个布尔表达式。 ::int 将其转换为数字,1 表示真,0 表示假。平均值就是一堆 1 和 0 的平均值——并且是真实值的比率。

    【讨论】:

      【解决方案2】:

      您可以使用条件总和来获得良好的价值并计算总数

      下面是详尽的代码示例

        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 
      

      为了你的结果

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

      或者按照 a_horse_with_no_name 的建议使用 count(*) filter()

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

      【讨论】:

      • 在 Postgres 中,您可以将 CASE 表达式简化为例如count(*) filter (where c = 'good')
      • @a_horse_with_no_name .. 正确。我习惯使用 CASE
      • @Abelisto:仍然使用整数除法,你需要(...)::numeric / count(*) 来避免这种情况
      • @a_horse_with_no_name 当然可以。但是在整数算术中x * 100 / y 通常比x / y * 100 更准确实际上在这个答案中结果总是0: select 99 / 100 * 100, 99 * 100 / 100;
      【解决方案3】:

      对于这种情况你需要使用条件AVG():

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

      请参阅demo

      【讨论】:

        猜你喜欢
        • 2020-07-31
        • 2011-06-01
        • 2021-01-10
        • 2017-05-13
        • 2019-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多