【问题标题】:Divide two counts from one select从一个选择中除以两个计数
【发布时间】:2013-10-29 23:29:57
【问题描述】:

我有一张这样的桌子:

date(timestamp) Error(integer)   someOtherColumns

我有一个查询要选择特定日期的所有行:

SELECT * from table
WHERE date::date = '2010-01-17'  

现在我需要计算 Error 等于 0 的所有行(从那天开始),然后除以所有行的计数(从那天开始)。

所以结果应该是这样的

Date(timestamp)      Percentage of failure
2010-01-17           0.30

数据库很大,有几百万行..

如果有人知道如何做到这一点,那就太好了——从一天到另一天。

Date(timestamp)      Percentage of failure
2010-01-17           0.30
2010-01-18           0.71
and so on

【问题讨论】:

  • BTW 不要使用保留字如date 作为列名。它可能会导致查询中出现一些令人讨厌的错误。
  • error 可以是NULL 吗?您是否需要几天的结果中有一行,而表中根本没有任何条目?

标签: sql postgresql select percentage


【解决方案1】:

这个呢(如果error 可能只有 1 和 0):

select
   date,
   sum(Error)::numeric / count(Error) as "Percentage of failure"
from Table1
group by date

或者,如果error 可以是任何整数:

select
   date,
   sum(case when Error > 0 then 1 end)::numeric / count(Error) as "Percentage of failure"
from Table1
group by date

刚刚发现我已经数过not 0(假设错误是在Error != 0 时),并且没有将空值计入帐户(不知道您想如何处理它)。所以这是另一个查询,它将空值视为 0,并以两种相反的方式计算失败百分比:

select
    date,
    round(count(nullif(Error, 0)) / count(*) ::numeric , 2) as "Percentage of failure",
    1- round(count(nullif(Error, 0)) / count(*) ::numeric , 2) as "Percentage of failure2"
from Table1
group by date
order by date;

sql fiddle demo

【讨论】:

  • 就是这样。谢谢你:)
  • @Roman Pekar:如果 count(*) 为 0,这将(或至少应该)除以 0 失败...
  • @Quandary 好吧.. 不要认为任何 SQL 查询都可以返回 count(*) = 0 的记录 :)
  • @Roman Pekar:啊,是的,我的错,你是对的,group by 通过省略没有活动的日子来拯救你。
【解决方案2】:

试试这个

select cast(data1.count1 as float)/ cast(data2.count2 as float) 
 from (
select count(*) as count1 from table date::date = '2010-01-17' and Error = 0) data1, 

(select count(*) as count1 from table date::date = '2010-01-17') data2

【讨论】:

    【解决方案3】:
    SELECT date
         , round(count((error = 0) OR NULL) / count(*)::numeric, 2) AS percent_fail
    FROM   tbl
    GROUP  BY 1
    ORDER  BY 1;
    

    如果error 可以是NULL,这甚至可以工作。

    -> SQLfiddle demo.

    在这个密切相关的问题下还有更多(包括对性能的影响):
    Compute percents from SUM() in the same SELECT sql query

    计数方法的比较和基准this related answer on dba.SE

    【讨论】:

    • @quin61:请务必点击链接以获取有关性能的信息。 count(*)count(col) 快一点,并且对 NULL 值也是安全的。严格来说,只要我们不知道该列是否可以为 NULL,Roman 的回答就是不正确的。
    【解决方案4】:

    您可以使用 generate_series 并从那里获取它。

    像这样:

    WITH CTE AS 
    (
         SELECT 
             m
            --,extract('year'  FROM m) AS theyear
            --,extract('month' FROM m) AS themonth
            --,extract('day' FROM m) AS theday
    
            ,(SELECT COUNT(*) AS cnt FROM  table WHERE date::date = m AND Error = 1) AS data1 
            ,(SELECT COUNT(*) AS cnt FROM  table WHERE date::date = m) AS data2 
        FROM  
        (
            SELECT generate_series('2012-04-01'::date, '2016-01-01'::date, interval '1 day') AS m
        ) AS g 
    ) -- END OF CTE 
    
    SELECT 
          m
         ,COALESCE(data1 * 100.0 / NULLIF(data2, 0.0), 0.0) AS ErrorPercentage
    FROM CTE
    

    查看详情: How to perform a select query in a DO block?

    【讨论】:

    • 它仍然给我:错误:在“WITH”第 1 行或附近出现语法错误:WITH CTE AS
    • @quin61:我不知道您的表格和日期字段是什么,可能是无效的日期,但该语句在我的机器上运行良好。
    猜你喜欢
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 2011-05-02
    • 1970-01-01
    • 2014-06-12
    • 1970-01-01
    • 2013-03-18
    • 2014-01-13
    相关资源
    最近更新 更多