我已经看到了有关此主题的几个问题,但是答案对我而言似乎没有用。
我必须在PostgreSQL 10.5中创建一个函数,该函数返回具有N个有效数字的数字。我已经针对此问题尝试了不同的解决方案,但是我遇到了特殊情况。在示例下面,其中nmNumber
是输入参数的数量,nmSf
是有效数字的数量。
SELECT round(nmNumber * power(10, nmSf-1-floor(log(abs(nmNumber ))))) / power(10, nmSf-1-floor(log(abs(nmNumber)))) result1,
round(nmNumber, cast(-floor(log(abs(nmNumber))) as integer)) result2,
floor(nmNumber / (10 ^ floor(log(nmNumber) - nmSf + 1))) * (10 ^ floor(log(nmNumber) - nmSf + 1)) result3;
如果nmNumber
= 0.0801和nmSf
= 2,则:
结果1 = 0.08; result2 = 0.08;结果3 = 0.08
鉴于以下三个结果,这是不正确的:
根据点3,上一个示例的正确结果是:0.080,而不是0.08,尽管从数学上看,它是相同的,但我必须从视觉上获得此结果。关于如何解决我的问题的一些想法?我想返回VARCHAR
来交换NUMERIC
是要提出的解决方案的一部分。
有些想法,或者我缺少一些东西。谢谢。
答案 0 :(得分:0)
这将实现您的要求:
CREATE OR REPLACE FUNCTION f_significant_nr(_nr numeric, _sf int, OUT _nr1 text) AS
$func$
DECLARE
_sign bool; -- record negative sign
_int int; -- length of integral part
_nr_text text; -- intermediate text state
BEGIN
IF _sf < 1 THEN
RAISE EXCEPTION '_sf must be > 0!';
ELSIF _nr IS NULL THEN
RETURN; -- returns NULL
ELSIF _nr = 0 THEN
_nr1 := '0'; RETURN;
ELSIF _sf >= length(translate(_nr::text, '-.','')) THEN -- not enough digits, optional shortcut
_nr1 := _nr; RETURN;
ELSIF abs(_nr) < 1 THEN
_nr1 := COALESCE(substring(_nr::text, '^.*?[1-9]\d{' || _sf-1 || '}'), _nr::text); RETURN;
ELSIF _nr < 0 THEN -- extract neg sign
_sign := true;
_nr := _nr * -1;
END IF;
_int := trunc(log(_nr))::int + 1; -- <= 0 was excluded above!
IF _sf < _int THEN -- fractional digits not touched
_nr1 := rpad(left(_nr::text, _sf), _int, '0');
ELSE
_nr1 := trunc(_nr)::text;
IF _sf > _int AND (_nr % 1) > 0 THEN -- _sf > _int and we have significant fractional digits
_nr_text := right((_nr % 1)::text, -1); -- remainder: ".123"
_nr1 := _nr1 || COALESCE(substring(_nr_text, '^.*?[1-9]\d{' || (_sf - _int - 1)::text || '}'), _nr_text);
END IF;
END IF;
IF _sign THEN
_nr1 := '-' || _nr1;
END IF;
END
$func$ LANGUAGE plpgsql;
db <>提琴here -带有测试用例。
处理所有您要扔的东西,包括NULL
,0
,0.000
或负数。
但是我对您的第3点表示怀疑。
答案 1 :(得分:0)
postgres知道如何做到这一点(甚至是第3点),您只需要问对它正确的方式即可。
create or replace function
sig_fig(num numeric,prec int) returns numeric
language sql as
$$
select to_char($1, '9.'||repeat('9',$2-1)||'EEEE')::numeric
$$;
创建一个格式字符串,产生科学的 带有3位数尾数的符号。用那个 将该数字转换为文本,然后将其转换回数字,从而产生具有许多有效数字的常规数字。
演示:
with v as ( values (3.14159),(1234567),(0.02),(1024),(42),(0.0098765),(-6666) ) select column1 ,sig_fig(column1,3) as "3sf" from v;
column1 | 3sf
-----------+---------
3.14159 | 3.14
1234567 | 1230000
0.02 | 0.0200
1024 | 1020
42 | 42.0
0.0098765 | 0.00988
-6666 | -6670
(7 rows)