看起来 Money
类型被描述为不推荐使用,详情请参见 此处。
我的应用程序需要存储货币,我应该使用哪种数据类型?Numeric、Money 还是 FLOAT?
看起来 Money
类型被描述为不推荐使用,详情请参见 此处。
我的应用程序需要存储货币,我应该使用哪种数据类型?Numeric、Money 还是 FLOAT?
您的来源并非官方。它可以追溯到2011年,我甚至不认识作者。如果货币类型被官方“不鼓励使用”,PostgreSQL会在手册中明确说明-但它没有这样做。
如需更正式的来源,请阅读pgsql-general中的此线程(仅本周!),其中包括来自核心开发人员D'Arcy J.M. Cain(money类型的原始作者)和Tom Lane的声明:
相关答案(及评论!)关于最近发布的改进:
基本上,money
的用途非常有限。Postgres Wiki 建议在除了那些狭义定义的情况下尽量避免使用它。相对于 numeric
,它的优点在于性能。decimal
只是 numeric
的别名,并且被广泛用于货币数据,是一种“任意精度”类型。The manual:
类型
numeric
可以存储具有非常大位数的数字。 特别推荐用于存储需要精确度的货币金额和其他数量。
个人而言,如果不涉及小数分钱(基本上是在货币有意义的情况下),我喜欢将货币存储为表示美分的 整数
。这比其他提到的选项更有效率。
money
类型实际已经被废弃。后来的版本中已经修复了这些问题并重新添加了该类型。个人而言,我喜欢将货币存储为代表“分”的整数
类型。 - Erwin Brandstetter你的选择如下:
bigint
:以分为单位存储金额。这是EFTPOS交易使用的方式。decimal(12,2)
:精确存储金额,仅保留两位小数。这是大多数总账软件使用的方式。float
:糟糕的想法 - 精度不足。这是一些天真的开发人员使用的方式。选项2是最常用且最易于使用的方法。将精度(在我的示例中为12,表示总共12个数字)设置为最适合您的大小或小巧即可。
请注意,如果您正在将多个计算结果的交易汇总为具有业务含义的单个值(例如涉及汇率),则精度应该更高,以提供精确的宏观价值;考虑使用类似于decimal(18,8)
的内容,使总和准确并且每个值都可以按照分的精度四舍五入显示。
numeric(15,4)
或numeric(15,6)
是一个好主意。 - Petrus Theron数值型数据,精度为强制的2个单位。不要使用浮点数或类似浮点数的数据类型来表示货币,因为如果这样做,当财务报告的结尾数字有+/-几美元时,人们会感到不满意。
就我所知,货币类型只是因为历史原因而保留的。
以1伊朗里亚尔 = 0.000030美元为例。如果使用少于5个小数位,则在转换后,1 IRR 将被四舍五入为0美元。虽然现在我们在谈论纷杂的货币,但我认为在处理货币时,你永远不能太过小心。
numeric(3,2)
will be able to store max 9.99
3-2 = 1
- Konrad使用64位整数存储为bigint
如果分(cents)不够精细,则存储在小货币单位中或使用大乘数创建较大的整数。我建议使用微美元,其中美元被分成100万份。
例如:$5,123.56
可以存储为 5123560000
微美元。
numeric(15,6)
? - Juliusz Gonerabigint
的最大值小 1000 倍以上。虽然有 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt,但它的支持有限(目前)并且存在一些注意事项(例如,在进行货币转换时,无法轻松地将其乘以浮点数)。考虑到您可以使用微元存储在 JS 整数中的最大值为 90 亿美元,这对于大多数情况可能仍然足够好。 - Juliusz Gonerabigint
可能也不够用。比特币提供8位小数的精度,门罗提供12位,以太坊则提供18位。事实上,以太坊虚拟机内部使用uint256
,这相当于4个 bigint
(无符号的,所以你可能只需使用 numeric(72,18)
)。话虽如此,对于某些应用程序来说,存储如此精确的值可能并不必要(例如,如果您对它们没有进行任何数学计算),因此我现在将坚持使用 bigint
。最坏的情况是,可以使用数据库迁移来解决 :) - Juliusz Gonera我把所有的货币字段设为:
numeric(15,6)
这似乎有些多余,但如果你甚至有一点可能需要处理多种货币,你将需要这么多精度来进行转换。无论我向用户展示什么,我总是以美元储存。这样我就可以根据当天的汇率轻松地转换到其他任何货币。
如果你从不处理多种货币,最糟糕的是你浪费了一些空间来存储一些零。
使用BigInt
来存储货币,将其作为表示最小货币单位的正整数(例如,100美分表示1.00美元,或者100日元表示¥100(一种零点货币))。这就是Stripe所做的——全球电子商务最重要的金融服务公司之一。
来源:请参见https://stripe.com/docs/currencies的“零点货币”
最终这将成为顶尖答案...
这不是直接的答案,而是一个关于为什么 float
不是最好的货币数据类型的例子。
由于浮点数在内部的表示方式,更容易出现舍入误差。
在我们自己的十进制系统中,在除以2或5以外的任何东西时,都会出现舍入误差,这些都是10的因数。在二进制中,只有2而没有5,所以即使是“干净”的小数,如0.2
(1/5),也存在风险。
如果您尝试以下操作,就可以看到这一点:
select
0.1::float + 0.2::float as floats, -- 0.30000000000000004
0.1::numeric + 0.2::numeric as numerics --- 0.3
;
这就是让审计员抓狂的事情。
个人建议是根据您的需求使用小数精度。如果您想要存储货币最小单位(例如分)的整数数字,并且在编程语言中处理小数存在问题,那么精度为0的小数可以是一个选择。
要确定所需的精度,需要考虑以下因素:
注意,您还需要在使用的编程语言中找到相应的数据类型。
有关更多详细信息和注意事项,请参见文章。