如何在PostgreSQL中将平均值四舍五入到小数点后两位?


191

我正在通过Ruby gem'sequel'使用PostgreSQL。

我试图将其舍入到小数点后两位。

这是我的代码:

SELECT ROUND(AVG(some_column),2)    
FROM table

我收到以下错误:

PG::Error: ERROR:  function round(double precision, integer) does 
not exist (Sequel::DatabaseError)

运行以下代码时没有错误:

SELECT ROUND(AVG(some_column))
FROM table

有人知道我在做什么错吗?


3
您的错误消息与您问题中的代码不匹配。
亩太短

除了语法错误外,这个与dba.SE密切相关的问题为在PostgreSQL中舍入双精度数字提供了一些启示
Erwin Brandstetter,2012年

@muistooshort,感谢您指出。它应该在“ avg”处说“ round”。编辑。
user1626730 2012年

为了搜索结果,我也从提示中得到以下提示:HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Vzzarr,

Answers:


263

PostgreSQL没有定义round(double precision, integer)。由于某些原因,@ Mike Sherrill'Cat Recall'在评论中解释,仅适用于需要精确度的回合版本numeric

regress=> SELECT round( float8 '3.1415927', 2 );
ERROR:  function round(double precision, integer) does not exist

regress=> \df *round*
                           List of functions
   Schema   |  Name  | Result data type | Argument data types |  Type  
------------+--------+------------------+---------------------+--------
 pg_catalog | dround | double precision | double precision    | normal
 pg_catalog | round  | double precision | double precision    | normal
 pg_catalog | round  | numeric          | numeric             | normal
 pg_catalog | round  | numeric          | numeric, integer    | normal
(4 rows)

regress=> SELECT round( CAST(float8 '3.1415927' as numeric), 2);
 round 
-------
  3.14
(1 row)

(在上面,请注意,这float8只是。的简写别名double precision。您可以看到PostgreSQL在输出中对其进行了扩展)。

您必须将要四舍五入的值转换numeric为使用的两个参数的形式round。只需追加::numeric简写形式,例如round(val::numeric,2)


如果您要格式化以显示给用户,请不要使用round。使用to_char(请参阅:手册中的数据类型格式化功能),它可以使您指定格式并为您提供text不受客户端语言可能对numeric值造成的任何怪异影响的结果。例如:

regress=> SELECT to_char(float8 '3.1415927', 'FM999999999.00');
    to_char    
---------------
 3.14
(1 row)

to_char将为格式舍入数字。该FM前缀告诉to_char你不想与前导空格任何填充。


嗯 当我尝试时ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);,我得到'0.314E1'。而且我已经编写了代码,ROUND(AVG(val),2)但仍然收到我在问题中描述的错误。
user1626730

我只是ROUND(CAST(FLOAT8 '3.1415927' AS NUMERIC),2);在PgAdmin和Ruby上运行。使用PgAdmin,我得到3.14,但是使用Ruby(使用他的Sequel gem),我得到的是“ 0.314E1”。我不知道为什么会这样...
user1626730

12
“出于某种奇怪的原因,需要精确度的回合版本仅适用于数字。” 浮点数是“有用的近似值”。如果您要求代码将浮点数四舍五入到小数点后两位,并返回另一个浮点数,则不能保证最接近“正确”答案的近似值在小数点后仅两位。数字是有效缩放的整数;他们没有那个问题。
Mike Sherrill'Cat Recall'

@Catcall好点-一个double版本的round将需要返回numericor(ugh)text,因此它也可能需要一个numeric参数。
Craig Ringer 2012年

6
对于那些试图找到@Catcall评论:现在是麦克谢里尔“猫召回”
18446744073709551615

88

还尝试使用旧的强制转换语法,

SELECT ROUND(AVG(some_column)::numeric,2)    
FROM table;

适用于任何版本的PostgreSQL。

某些PostgreSQL函数中缺少重载,为什么(???):我认为“这是一个不足”(!),但是@ CraigRinger,@ Catcall和PostgreSQL团队同意“ pg的历史依据”。

PS:关于舍入的另一点是准确性,请查看@IanKenney的答案


重载作为投放策略

您可以使用以下方法重载 ROUND函数:

 CREATE FUNCTION ROUND(float,int) RETURNS NUMERIC AS $$
    SELECT ROUND($1::numeric,$2);
 $$ language SQL IMMUTABLE;

现在您的指令可以正常工作,尝试(在函数创建之后)

 SELECT round(1/3.,4); -- 0.3333 numeric

但它返回NUMERIC类型...为了保留第一个commom使用超载,我们可以在提供TEXT参数时返回FLOAT类型,

 CREATE FUNCTION ROUND(float, text, int DEFAULT 0) 
 RETURNS FLOAT AS $$
    SELECT CASE WHEN $2='dec'
                THEN ROUND($1::numeric,$3)::float
                -- ... WHEN $2='hex' THEN ... WHEN $2='bin' THEN... complete!
                ELSE 'NaN'::float  -- like an error message 
            END;
 $$ language SQL IMMUTABLE;

尝试

 SELECT round(1/3.,'dec',4);   -- 0.3333 float!
 SELECT round(2.8+1/3.,'dec',1); -- 3.1 float!
 SELECT round(2.8+1/3.,'dec'::text); -- need to cast string? pg bug 

PS:\df round超载后检查,会显示类似的内容,

架构| 姓名| 结果数据类型| 参数数据类型
------------ + ------- + ------------------ + ---------- ------------------
 myschema | 圆形 双精度| 双精度,文本,整数
 myschema | 圆形 数字| 双精度,整数
 pg_catalog | 圆形 双精度| 双精度            
 pg_catalog | 圆形 数字| 数字   
 pg_catalog | 圆形 数字| 数字,整数          

这些pg_catalog函数是默认函数,请参见内置数学函数手册


38

试试这个:

SELECT to_char (2/3::float, 'FM999999990.00');
-- RESULT: 0.67

或者简单地:

SELECT round (2/3::DECIMAL, 2)::TEXT
-- RESULT: 0.67

5
我发现这是我每天对这个问题的答案更加简洁明了。:弓:
craastad

2
同样在这里!非常简短且有用的解决方案。
阿列克谢·沙布拉莫夫

7

您可以使用下面的功能

 SELECT TRUNC(14.568,2);

结果将显示:

14.56

您还可以将变量转换为所需的类型:

 SELECT TRUNC(YOUR_VAR::numeric,2)

3

根据Bryan的响应,您可以执行此操作以限制查询中的小数。我从km / h转换为m / s,并在图表中显示,但是当在图表中显示时,看起来很奇怪。在查询中进行计算时看起来不错。这是在PostgreSQL 9.5.1上。

select date,(wind_speed/3.6)::numeric(7,1) from readings;


1

错误:函数舍入(双精度,整数)不存在

解决方案:您需要添加类型转换,然后它才能工作

例如: round(extract(second from job_end_time_t)::integer,0)


0

选择ROUND(SUM(amount):: numeric,2)作为total_amount FROM交易

给出:200234.08

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.