use*_*117 22 postgresql datatypes count cast
我正在尝试运行以下查询以提供patients表中具有refinst列值的行的百分比。我一直得到0的结果。
select (count (refinst) / (select count(*) from patients) * 100) as "Formula"
from patients;
Run Code Online (Sandbox Code Playgroud)
该表有 15556 行,并select count(refinst) from patients告诉我其中 1446行在列中有值refinst。我想从查询中得到的响应是 30.62 ( 1446/15556*100=30.62XXXXX,四舍五入到两位小数)。
我很确定它与计数结果的数据类型(我假设是整数)有关。如果我将一个整数除以一个整数并且结果小于 0,它会被截断为 0 是否正确?如果是这种情况,有人可以告诉我如何将计数结果转换为带有 2 个小数位的数字,以便结果也四舍五入到 2 个小数位吗?
我确信有比多个 count 语句更好的方法来编写此代码。我正在寻找一种更高效的方式来编写这个查询。
Erw*_*ter 27
SELECT (count(refinst) * 100)::numeric / NULLIF(count(*), 0) AS refinst_pct
-- count(refinst) * 100.0 / NULLIF(count(*), 0) AS refinst_pct -- simpler
FROM patients;
Run Code Online (Sandbox Code Playgroud)
千万不能使用子查询。两个聚合都可以从同一个查询中派生出来。更便宜。
此外,这不是窗口函数的情况,因为您想要计算单个结果,而不是每行一个结果。
转换为任何支持小数位数的数字类型,例如@a_horse 已经解释过。
由于您想要round()两个小数位,我建议numeric(这与decimalPostgres 中的相同)。
投射一个参与计算的值就足够了,最好是第一个。Postgres 会自动适应不会丢失信息的类型。
或者,更简单:因为我们无论如何都要进行乘法运算,所以使用一个由于小数点 ( )而被自动强制转换的数字常量。numeric100.0
在除法之前先乘法通常是个好主意。这通常可以最大限度地减少舍入误差并且更便宜。
在这种情况下,第一个乘法 ( count(refinst) * 100) 可以用廉价而精确的integer算术计算。只有这样我们才能投射到numeric并除以下一个integer(我们不会额外投射)。
NULLIF(count(*), 0)防止被零除(引发异常)。如果根本没有行,我们将 NULL 作为(未知)百分比。
四舍五入为两位小数:
SELECT round((count(refinst) * 100)::numeric / NULLIF(count(*), 0), 2) AS refinst_pct
FROM patients;
Run Code Online (Sandbox Code Playgroud)
小智 3
您需要将除法中涉及的每个数字转换为支持小数的类型:
select (count(refinst)::decimal / (select count(*) from patients)::decimal) * 100 as "Formula"
from patients;
Run Code Online (Sandbox Code Playgroud)
您可能还想尝试窗口函数而不是标量子查询。它可能会更快:
select (count(refinst)::decimal / (count(*) over ())::decimal) * 100 as "Formula"
from patients;
Run Code Online (Sandbox Code Playgroud)