【问题标题】:How to truncate double precision value in PostgreSQL by keeping exactly first two decimals?如何通过保留前两位小数来截断 PostgreSQL 中的双精度值?
【发布时间】:2020-10-05 22:51:32
【问题描述】:

当我在 PostgreSQL 11.8 中使用 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] 错误:函数 round(双精度,整数)不存在

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

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(非常感谢任何建议/帮助)?

P.S. PostgreSQL 版本是 11.8

【问题讨论】:

  • 您的确切 PostgreSQL 版本是多少?我无法在 12.3 中重现。 found_book.price 的数据类型是什么?
  • @pifor:它是 PostgreSQL 11.8
  • 您必须添加一个完整的 SQL 语句来显示不需要的舍入。我不确定你到底在做什么。
  • found_book.price的原始数据类型是什么?将结果传递给json_build_object 应该没有关系。
  • @Bergi: 这是double precision (found_book.price)

标签: json postgresql rounding plpgsql truncated


【解决方案1】:

PostgreSQL 11.812.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)

但请注意:

注意:extra_float_digits 设置控制额外的数量 转换浮点值时包含的有效数字 到文本输出。默认值为 0,输出为 在 PostgreSQL 支持的每个平台上都相同。增加它会 产生更准确地表示存储值的输出,但是 可能无法携带。

【讨论】:

  • 我已经用我正在使用的 json_build_object() 函数的代码更新了我的问题,所以很明显我不能将数值作为字符串传递(就像在你的第一个和第二个示例中一样)。跨度>
  • 奇怪,我无法在带有 PostgreSQL 12.3 的 Fedora 30 上重现它。
  • 我同意:我无法使用 PG 12.3 进行复制。但它适用于 Centos 7.8.2003 上的 PG 11.8。
  • @NikolaS:使用 psql \timing 运行 3 次转换时使用 SELECT 进行快速测试不会显示开销,而仅使用 SELECT 19...` 显示数字而不进行任何转换。应该没有性能问题。
  • @NikolaS:是的,您需要找到解决方法。如果可能,请尝试切换到numeric,因为作为文档。说:如果您需要精确的存储和计算(例如货币金额),请改用数字类型。
【解决方案2】:

正如@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' 键的值传递不起作用。

感谢您的帮助。 :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-18
    • 1970-01-01
    • 1970-01-01
    • 2019-11-17
    • 2019-03-13
    相关资源
    最近更新 更多