round(cast (41.0255 as numeric),3) ==> 41.026
由于我们需要一个返回41.025的圆函数(非常令人惊讶)在Postgresql中没有这样的函数(我们使用的是9.1.5),我们编写了一个“包装”函数,在第一个版本中它非常天真,粗糙……但由于缺乏对plpgsql中此类问题的本机支持,我们没有找到更好的东西.
代码如下所示.问题是它对我们的目的来说太慢了.
你能建议一个更好的方法来处理这个任务吗?
这是代码:
CREATE OR REPLACE FUNCTION round_half_down(numeric,integer) RETURNS numeric AS $$ DECLARE arg ALIAS FOR $1; rnd ALIAS FOR $2; tmp1 numeric; res numeric; BEGIN tmp1:=arg; IF cast(tmp1 as varchar) ~ '5$' THEN res:=trunc(arg,rnd); ELSE res:=round(arg,rnd); END IF; RETURN res; END; $$LANGUAGE plpgsql;
我需要转换数值并使用正则表达式…这就是(我猜)杀死表演的东西.
您知道:我们需要这个,因为我们必须比较存储在两个不同列(在两个不同的表上)但具有不同数值数据类型的数字:一个是double,一个是real.问题是当插入真实数据类型列时,Postgresql执行ROUND HALF DOWN,而它不通过其数学函数提供这样的选项!
编辑:
该功能实际上是错误的.是第一次快速重写,试图提高工作功能的性能,但速度很慢.
行为必须符合以下条件:
如果从舍入中推出的十进制数是< = 5 => TRUNC
ELSE围捕.
一些例子:
select round_half_down(cast (41.002555 as numeric),3) -- 41.002 select round_half_down(cast (41.002555 as numeric),4) -- 41.0025 select round_half_down(cast (41.002555 as numeric),5) -- 41.00255
select round(cast (41.002555 as numeric),3) -- 41.003
解决方法
We have to compare numbers that were stored in two different columns
(on two different tables) but with different numeric data type: one is
double and one is real.
这应该非常快速和简单:
SELECT dp_col,real_col FROM tbl WHERE dp_col::real = real_col
基本上,只需将双精度数转换为实数即可进行比较.
如果这对你不起作用,这个sql函数应该做一个合适的工作并且工作得更快:
CREATE OR REPLACE FUNCTION round_half_down1(numeric,int) RETURNS numeric LANGUAGE sql AS $func$ SELECT CASE WHEN abs($1%0.1^$2) < .6 * 0.1^$2 THEN trunc($1,$2) ELSE round($1,$2) END; $func$
现在修复了负数,并在评论中输入@sufleR.
您也可以使用包含的CASE表达式.
% .. modulo operator
^ .. exponentiation
这是一个可用于基准测试的快速测试:
SELECT n -- Total runtime: 36.524 ms,round_half_down1(n,3) -- Total runtime: 70.493 ms,round_down_to_decimal_places(n,3) -- Total runtime: 74.690 ms,round_half_down(n,3) -- Total runtime: 82.191 ms FROM (SELECT random()::numeric AS n FROM generate_series(1,10000)) x WHERE round_down_to_decimal_places(n,3) <> round_half_down1(n,3)