如何通过准确保留前两位小数来截断 PostgreSQL 中的双精度值?

How to truncate double precision value in PostgreSQL by keeping exactly first two decimals?

我正在尝试在 PostgreSQL 11.8json_build_object() 中使用 json_build_object() 函数构建 json 时截断 双精度 但没有运气。更准确地说,我试图将 19.9899999999999984 数字截断为仅两位小数,但确保它不会将其四舍五入为 20.00(这是它所做的),而是将其保持在 19.98.

顺便说一句,到目前为止我尝试使用的是:
1) TRUNC(found_book.price::numeric, 2) 我得到值 20.00
2) ROUND(found_book.price::numeric, 2) 我得到值 19.99 -> 到目前为止这是最接近的值但不是我需要的值
3) ROUND(found_book.price::double precision, 2) 我得到

[42883] ERROR: function round(double precision, integer) does not exist

这也是我正在使用的完整代码:

create or replace function public.get_book_by_book_id8(b_id bigint) returns json as
$BODY$
declare
    found_book book;
    book_authors json;
    book_categories json;
    book_price double precision;
begin
    -- Load book data:
    select * into found_book
    from book b2
    where b2.book_id  = b_id;

    -- Get assigned authors
    select case when count(x) = 0 then '[]' else json_agg(x) end into book_authors
    from (select aut.*
        from book b
        inner join author_book as ab on b.book_id = ab.book_id
        inner join author as aut on ab.author_id = aut.author_id
        where b.book_id = b_id) x;

    -- Get assigned categories
    select case when count(y) = 0 then '[]' else json_agg(y) end into book_categories
    from (select cat.*
        from book b
        inner join category_book as cb on b.book_id = cb.book_id
        inner join category as cat on cb.category_id = cat.category_id
        where b.book_id = b_id) y;

    book_price = trunc(found_book.price, 2);
    -- Build the JSON response:
    return (select json_build_object(
        'book_id', found_book.book_id,
        'title', found_book.title,
        'price', book_price,
        'amount', found_book.amount,
        'is_deleted', found_book.is_deleted,
        'authors', book_authors,
        'categories', book_categories
    ));
end
$BODY$
language 'plpgsql';

select get_book_by_book_id8(186);

我如何实现只保留前两位十进制数字 19.98(非常感谢任何 suggestion/help)?

P.S. PostgreSQL 版本为 11.8

PostgreSQL 11.8 or 12.3 我无法复制:

# select trunc('19.9899999999999984'::numeric, 2);
 trunc 
-------
 19.98
(1 row)

# select trunc(19.9899999999999984::numeric, 2);
 trunc 
-------
 19.98
(1 row)

# select trunc(19.9899999999999984, 2);
 trunc 
-------
 19.98
(1 row)

实际上我可以使用正确的类型和特殊设置进行复制:

# set extra_float_digits=0;
SET
# select trunc(19.9899999999999984::double precision::text::numeric, 2);
 trunc 
-------
 19.99
(1 row)

以及一个可能的解决方案:

# show extra_float_digits;
 extra_float_digits 
--------------------
 3
(1 row)

select  trunc(19.9899999999999984::double precision::text::numeric, 2);
 trunc 
-------
 19.98
(1 row)

但请注意:

Note: The extra_float_digits setting controls the number of extra significant digits included when a floating point value is converted to text for output. With the default value of 0, the output is the same on every platform supported by PostgreSQL. Increasing it will produce output that more accurately represents the stored value, but may be unportable.

正如@pifor 所建议的那样,我已经设法通过直接将 trunc(found_book.price::double precision::text::numeric, 2) 作为 json_build_object 中的值传递来完成它,如下所示:

json_build_object(
        'book_id', found_book.book_id,
        'title', found_book.title,
        'price', trunc(found_book.price::double precision::text::numeric, 2),
        'amount', found_book.amount,
        'is_deleted', found_book.is_deleted,
        'authors', book_authors,
        'categories', book_categories
    )

使用 book_price = trunc(found_book.price::double precision::text::numeric, 2); 并将其作为值传递给 'price' 键无效。

感谢您的帮助。 :)