表中my_obj
有两个整数字段:
(value_a integer, value_b integer);
我试着计算一下有多少次value_a = value_b
,我想用百分比表示这个比率。
这是我尝试过的代码:
select sum(case when o.value_a = o.value_b then 1 else 0 end) as nb_ok,
sum(case when o.value_a != o.value_b then 1 else 0 end) as nb_not_ok,
compute_percent(nb_ok,nb_not_ok)
from my_obj as o
group by o.property_name;
compute_percent
是一个简单的存储过程(a * 100) / (a + b)
但 PostgreSQL 抱怨该列nb_ok
不存在。
你会如何正确地做到这一点?
我将 PostgreSQL 9.1 与 Ubuntu 12.04 一起使用。
这个问题的内涵远比看上去的要复杂。
简易版
This is much更快更简单:
SELECT property_name
,(count(value_a = value_b OR NULL) * 100) / count(*) AS pct
FROM my_obj
GROUP BY 1;
Result:
property_name | pct
--------------+----
prop_1 | 17
prop_2 | 43
How?
你根本不需要这个函数。
而不是数数value_b
(你不需要开始)并计算总数,使用count(*)
为总数。更快、更简单。
这假设你没有NULL
价值观。 IE。两列均已定义NOT NULL
。您的问题中缺少该信息。
如果没有,您的原始查询是可能没有按照你的想法去做。如果任何值为 NULL,则您的版本根本不计算该行。你甚至可以激怒被零除这种方式例外。
此版本也适用于 NULL。count(*)
生成所有行的计数,无论值如何。
-
以下是计数的工作原理:
TRUE OR NULL = TRUE
FALSE OR NULL = NULL
count()
忽略 NULL 值。瞧。
-
运算符优先级管辖那=
之前绑定OR
。您可以添加括号以使其更清晰:
count ((value_a = value_b) OR FALSE)
-
你可以用同样的方法
count NULLIF(<expression>, FALSE)
结果类型为count()
is bigint
默认情况下。
一个师bigint / bigint
, 截断小数位.
包括小数位
Use 100.0
(带小数位)强制计算为numeric
从而保留小数位。
您可能想使用round()有了这个:
SELECT property_name
,round((count(value_a = value_b OR NULL) * 100.0) / count(*), 2) AS pct
FROM my_obj
GROUP BY 1;
Result:
property_name | pct
--------------+-------
prop_1 | 17.23
prop_2 | 43.09
作为旁白:
I use value_a
代替valueA
。不要在 PostgreSQL 中使用不带引号的大小写混合标识符。我见过太多因这种愚蠢行为而产生的令人绝望的问题。如果您想知道我在说什么,请阅读本章标识符和关键词在手册中。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)