使用Java的PostgreSQL上的货币数据 NUMERIC/DECIMAL 四舍五入和NaN BigDecimal

2022-09-02 09:05:33

我正在编写一个挖掘货币兑换数据的Java程序。数据可以在小数点中包含多个数字,例如“0.973047”。经过一些研究,我发现BigDecimal是Java的正确数据类型,但是我应该为PostgreSQL使用哪种数据类型?


答案 1

NUMERIC/DECIMAL

正如Joachim Isaksson所说,您希望使用NUMIFICY / DECIMAL类型作为任意精度类型。

关于 /的两个要点:NUMERICDECIMAL

  • 请仔细阅读本文档,了解应指定小数位数以避免默认小数位数 0,这意味着小数分数被切除的整数值。虽然这是Postgres偏离标准SQL的地方之一(为您提供任何扩展到实现限制的地方)。因此,未能指定规模是一个糟糕的选择。
  • 根据SQL标准,SQL类型和是接近的,但不完全相同。在 SQL:92 中,将遵循您指定的精度,而对于数据库服务器,则允许添加超出您指定范围的附加精度。在这里,Postgres再次偏离了标准,两者都被记录为等效的。NUMERICDECIMALNUMERICDECIMALNUMERICDECIMAL

条款:

  • 精度是数字中的总位数。
  • 小数位数是小数点(小数点)右侧的位数。
  • ( 精度 - 小数位数 ) = 小数点左侧的位数(整数部分)。

明确项目的精度和规模规格:


  • 精度必须足够大,以处理将来可能需要的较大数字。意义。。。也许你的应用现在的工作金额为数千美元,但将来必须执行最终达到数百万美元的汇总报告。

  • 对于某些会计目的,您可能需要存储最小货币金额的一小部分。意义。。。超过3或4个小数位,而不是美元一分钱所需的2

避免类型MONEY

Postgres也提供了MONEY类型。这听起来可能是正确的,但对于大多数目的来说可能不是最好的。一个缺点是,规模是由基于区域设置的数据库范围的配置设置设置的。因此,当您切换服务器或进行其他更改时,该设置很容易发生变化。此外,您无法控制特定列的该设置,而可以对类型的每列设置小数位数。最后,不是标准 SQL 数据类型列表中所示的标准 SQL。Postgres包括为了方便人们从其他数据库系统移植数据。MONEYNUMERICMONEYMONEY

移动小数点

有些人采用的另一种方法是移动小数点,并且只存储在大整数数据类型中。

例如,如果将 USD 美元存储到便士,则将任何给定的小数乘以 100,转换为整数类型,然后继续。例如,$123.45 变为整数 12,345。

这种方法的好处是执行时间更快。对整数执行等操作时非常快。整数的另一个好处是内存使用量较少。sum

我发现这种方法很烦人,令人困惑且有风险。烦人,因为计算机应该为我们工作,而不是反对我们。有风险,因为一些程序员或用户可能忽略了乘法/除法以转换回小数,给出不正确的结果。如果在没有良好支持准确小数的系统中工作,则此方法可能是一种可接受的解决方法。

我看不出当我们在SQL中/和Java中的BigDecimal时移动小数点有任何好处。DECIMALNUMERIC

四舍五入和NaN

在应用的编程中,以及在 Postgres 服务器端进行的任何计算中,请非常小心,并注意小数部分的舍入和截断。并测试无意中弹出的NaN

在两边,应用程序和Postgres,始终避免浮点数据类型为金钱工作。浮点数是为性能速度而设计的,但以牺牲准确性为代价计算可能会导致小数点中看似疯狂的额外数字。不利于财务/金钱或其他准确性很重要的目的。

BigDecimal

是的,在Java中,您希望BigDecimal作为任意精度类型。 速度较慢,占用更多内存,但会准确存储您的金额。SQL / 应该映射到这里StackOverflow 上讨论的内容。BigDecimalNUMERICDECIMALBigDecimal

BigDecimal是Java最好的事情之一。我不知道还有任何其他平台具有类似的类,特别是一个实现良好且经过精心打磨的平台,多年来进行了重大增强和修复。

使用绝对比使用Java的浮点类型慢,& .但在现实世界的应用程序中,我怀疑你的金钱计算是否会成为任何瓶颈。此外,您或您的客户想要哪一个:最快的货币计算,还是准确的货币计算?BigDecimalfloatdouble


答案 2