问题
I have table with real column type with example values:
123456,12
0,12345678
And code in stored procedure:
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;
Here is output:
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
DB table with columns NUMERIC(19,2):
km casting rounding
0.12 0.12 0.12
123456.00 123456.00 123456.00
Why do cast and round functions not work for the value 123456.12?
回答1:
real is a lossy, inexact floating-point type. It only uses 4 bytes for storage and cannot store the presented numeric literals precisely to begin with. In addition, implementation details depend on your platform. Consider the chapter "Floating-Point Types" in the manual.
There is nothing wrong with either round() or cast(). For exact results, you'd have to use numeric to begin with.
Function audit
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;
- Do not quote the language name
plpgsql. It's an identifier. Makes no sense to round to 2 fractional digits after casting to
numeric(16,2), which forcibly rounds already. Either - or ..round(abs_km:: numeric(16,2), 2) as roundround(abs_km::numeric, 2) as round abs_km::numeric(16,2) as round
Finally, you need to upgrade to a current version. Postgres 8.3 has reached EOL and is unsupported.
来源:https://stackoverflow.com/questions/21576685/how-to-round-real-type-to-numeric