如何将REAL类型舍入为NUMERIC?

时间:2014-02-05 12:00:42

标签: postgresql stored-procedures types plpgsql postgresql-8.3

我的表格中包含real列类型,其中包含示例值:

123456,12
0,12345678

存储过程中的代码:

CREATE OR REPLACE FUNCTION test3()
  RETURNS integer AS
$BODY$
   DECLARE
      rec    RECORD;
   BEGIN

      FOR rec IN 

         SELECT
         gme.abs_km as km,
         CAST(gme.abs_km as numeric) as cast,         
         round(gme.abs_km:: numeric(16,2), 2) as round
         FROM gps_entry gme
      LOOP

         RAISE NOTICE 'Km: % , cast: % , round: %', rec.km, rec.cast, rec.round;
         INSERT INTO test (km, casting, rounding) VALUES (rec.km, rec.cast, rec.round);

      END LOOP;
      RETURN 1;      
   END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE;

这是输出:

2014-02-05 12:49:53 CET NOTICE:  Km: 0.12345678 , cast: 0.123457 , round: 0.12
2014-02-05 12:49:53 CET NOTICE:  Km: 123456.12 , cast: 123456 , round: 123456.00

包含NUMERIC(19,2)列的数据库表:

km        casting   rounding
0.12      0.12      0.12

123456.00 123456.00 123456.00

为什么castround函数不适用于值123456.12

1 个答案:

答案 0 :(得分:5)

real是一种有缺陷的,不精确的浮点类型。它只使用4个字节进行存储,并且不能精确地存储所提供的数字文字。此外,实施细节取决于您的平台。考虑the chapter "Floating-Point Types" in the manual.

round()cast()都没有错。要获得准确的结果,您必须先使用numeric

功能审核

CREATE OR REPLACE FUNCTION test3()
  RETURNS void AS
$func$
DECLARE
   r record;
BEGIN
   FOR r IN 
      SELECT abs_km AS km
            ,cast(abs_km AS numeric) AS km_cast
            ,round(abs_km::numeric, 2) AS km_round
      FROM   gps_entry
   LOOP
      RAISE NOTICE 'km: % , km_cast: % , km_round: %'
                  , r.km, r.km_cast, r.km_round;
      INSERT INTO test (km, casting, rounding)
      VALUES (r.km, r.km_cast, r.km_round);
   END LOOP;    
END
$func$ LANGUAGE plpgsql;
  • 不要引用语言名称plpgsql。这是一个标识符。
  • 在投射到numeric(16,2)之后舍入到2个小数位是没有意义的,而round(abs_km:: numeric(16,2), 2) as round round(abs_km::numeric, 2) as round abs_km::numeric(16,2) as round已强制舍入。要么 - 或..

    {{1}}

最后,您需要升级到当前版本。 Postgres 8.3 has reached EOL and is unsupported.