ILi*_*cos 43 postgresql amazon-redshift
我正在尝试编写一个只计算符合条件的行的查询.
例如,在MySQL中我会这样写:
SELECT
COUNT(IF(grade < 70), 1, NULL)
FROM
grades
ORDER BY
id DESC;
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试在Redshift上执行此操作时,它会返回以下错误:
错误:函数if(布尔,整数,"未知")不存在
提示:没有函数匹配给定的名称和参数类型.您可能需要添加显式类型转换.
我检查了条件语句的文档,我找到了
NULLIF(value1, value2)
但它只比较value1和value2,如果这些值相等,则返回null.
我找不到一个简单的IF语句,乍一看我找不到办法去做我想做的事情.
我试图使用CASE表达式,但我没有得到我想要的结果:
SELECT
CASE
WHEN grade < 70 THEN COUNT(rank)
ELSE COUNT(rank)
END
FROM
grades
Run Code Online (Sandbox Code Playgroud)
这是我想要计算的方式:
失败(等级<70)
平均值(70 <=等级<80)
好(80 <=等级<90)
优秀(90 <=等级<= 100)
这就是我期望看到的结果:
+========+=========+======+===========+
| failed | average | good | excellent |
+========+=========+======+===========+
| 4 | 2 | 1 | 4 |
+========+=========+======+===========+
Run Code Online (Sandbox Code Playgroud)
但是我得到了这个:
+========+=========+======+===========+
| failed | average | good | excellent |
+========+=========+======+===========+
| 11 | 11 | 11 | 11 |
+========+=========+======+===========+
Run Code Online (Sandbox Code Playgroud)
我希望有人能指出我正确的方向!
如果这有助于这里的一些示例信息
CREATE TABLE grades(
grade integer DEFAULT 0,
);
INSERT INTO grades(grade) VALUES(69, 50, 55, 60, 75, 70, 87, 100, 100, 98, 94);
Run Code Online (Sandbox Code Playgroud)
yie*_*ood 131
首先,你在这里遇到的问题是你说的是"如果等级小于70,这个案例表达式的值是count(rank).否则,这个表达式的值是count(rank) ".所以,在任何一种情况下,你总是得到相同的价值.
SELECT
CASE
WHEN grade < 70 THEN COUNT(rank)
ELSE COUNT(rank)
END
FROM
grades
Run Code Online (Sandbox Code Playgroud)
count()只计算非空值,所以通常你会看到完成你正在尝试的模式是这样的:
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
Run Code Online (Sandbox Code Playgroud)
这样,case表达式仅在测试表达式为true时计算为1,否则为null.然后count()将只计算非null实例,即当测试表达式为true时,它应该为您提供所需的内容.
编辑:作为旁注,请注意这与您最初编写此文件的方式完全相同count(if(test, true-value, false-value)),仅重写为count(case when test then true-value end)(并且由于else未提供给案例,因此null为false值).
编辑:postgres 9.4在原始交换后几个月发布.该版本引入了聚合过滤器,可以使这样的场景看起来更好更清晰.这个答案仍然偶尔有一些赞成,所以如果你偶然发现并使用更新的postgres(即9.4+),你可能会想要考虑这个等效的版本:
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
Run Code Online (Sandbox Code Playgroud)
小智 11
另一种方法:
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
Run Code Online (Sandbox Code Playgroud)
如果您想按分类列对计数进行分组,则可以正常工作.
@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
Run Code Online (Sandbox Code Playgroud)
但是既然你谈到了NULLIF(value1, value2),那么有一种 nullif 方法可以给出相同的结果:
select count(nullif(grade < 70 ,true)) as failed from grades;
仅红移
对于懒惰的打字者,这里有一个COUNTIF基于@user1509107答案构建的“”总和整数转换版本:
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
55804 次 |
| 最近记录: |