Postgresql 在红移/Postgres中,如何计算满足条件的行数?

Postgresql 在红移/Postgres中,如何计算满足条件的行数?,postgresql,amazon-web-services,amazon-redshift,Postgresql,Amazon Web Services,Amazon Redshift,我正在尝试编写一个只计算满足条件的行的查询 例如,在MySQL中,我会这样写: SELECT COUNT(IF(grade < 70), 1, NULL) FROM grades ORDER BY id DESC; 这是我计算事物的方式: 不合格(等级

我正在尝试编写一个只计算满足条件的行的查询

例如,在MySQL中,我会这样写:

SELECT
    COUNT(IF(grade < 70), 1, NULL)
FROM
    grades
ORDER BY
    id DESC;
这是我计算事物的方式:

  • 不合格(等级<70)


  • 平均值(70首先,你在这里遇到的问题是,你说的是“如果分数小于70,这个case表达式的值是count(rank)。否则,这个表达式的值是count(rank)。”因此,在任何一种情况下,你总是得到相同的值

    SELECT 
        CASE
            WHEN grade < 70 THEN COUNT(rank)
            ELSE COUNT(rank)
        END
    FROM
       grades
    
    另一种方法:

    SELECT 
        sum(CASE WHEN grade < 70 THEN 1 else 0 END) as grade_less_than_70,
        sum(CASE WHEN grade >= 70 and grade < 80 THEN 1 else 0 END) as grade_between_70_and_80
    FROM
       grades
    
    选择
    求和(如果等级<70,则为1,否则为0),作为等级小于等级70,
    求和(当等级>=70且等级<80时,则为1,否则为0)作为等级在等级70和等级80之间
    从…起
    分数
    

    如果您希望按分类列对计数进行分组,则可以正常工作。

    由@yieldsfalsehood给出的解决方案非常有效:

    SELECT
        count(*) filter (where grade < 70) as grade_less_than_70,
        count(*) filter (where grade >= 70 and grade < 80) as grade_between_70_and_80
    FROM
        grades
    
    选择
    将(*)过滤器(其中等级<70)计数为等级小于等级70,
    将(*)过滤器(其中等级>=70且等级<80)计数为等级70和等级80之间的等级
    从…起
    分数
    
    但既然您谈到了
    NULLIF(value1,value2)
    ,那么NULLIF有一种方法可以给出相同的结果:

    选择计数(nullif(grade<70,true))作为从grades中失败;

    仅限红移

    对于惰性打字机,这里有一个“
    COUNTIF
    ”和整数转换版本,它构建在@user1509107 answer之上:

    SELECT 
        SUM((grade < 70)::INT) AS grade_less_than_70,
        SUM((grade >= 70 AND grade < 80)::INT) AS grade_between_70_and_80
    FROM
       grades
    
    选择
    总和((等级<70)::INT)作为等级小于70,
    总和((等级>=70和等级<80)::INT)作为等级在等级70和等级80之间
    从…起
    分数
    
    太棒了!这正是我需要的。虽然我觉得有点奇怪,postgres没有提供简单的IF指令。我猜CASE..WHEN..ELSE做同样的工作,但仍然是。IF几乎是行业标准。CASE是官方标准;)IF()函数是MySQL,它是iif()在SQL Server中,
    过滤器
    显然也比其他选项快。请看,您是否希望在两者之间查找运算符?有趣的答案,显然更难阅读和理解,并且依赖于布尔
    true
    转换为1和
    false
    转换为0的特定行为。我怀疑类型转换的性能不如literal math case语句表达式,但我希望看到一些基准测试。在回答列表中添加一些基准测试仍然很有用。在postgres中,最好的选择是相对较新的
    过滤器
    表达式
    
    SELECT 
        CASE
            WHEN grade < 70 THEN COUNT(rank)
            ELSE COUNT(rank)
        END
    FROM
       grades
    
    SELECT 
        count(CASE WHEN grade < 70 THEN 1 END) as grade_less_than_70,
        count(CASE WHEN grade >= 70 and grade < 80 THEN 1 END) as grade_between_70_and_80
    FROM
       grades
    
    SELECT
        count(*) filter (where grade < 70) as grade_less_than_70,
        count(*) filter (where grade >= 70 and grade < 80) as grade_between_70_and_80
    FROM
       grades
    
    SELECT 
        sum(CASE WHEN grade < 70 THEN 1 else 0 END) as grade_less_than_70,
        sum(CASE WHEN grade >= 70 and grade < 80 THEN 1 else 0 END) as grade_between_70_and_80
    FROM
       grades
    
    SELECT
        count(*) filter (where grade < 70) as grade_less_than_70,
        count(*) filter (where grade >= 70 and grade < 80) as grade_between_70_and_80
    FROM
        grades
    
    SELECT 
        SUM((grade < 70)::INT) AS grade_less_than_70,
        SUM((grade >= 70 AND grade < 80)::INT) AS grade_between_70_and_80
    FROM
       grades