将资金存入小数列 – 什么精度和规模?

我正在使用一个十进制的列来存储数据库中的货币值,今天我想知道使用什么精度和规模。

由于据说固定宽度的char列更有效率,所以我认为对于十进制列也是如此。 是吗?

我应该使用什么精度和规模? 我在想精度24/8。 这是矫枉过正,不够还是不好?


这是我决定要做的事情:

  • 将转换率(如果适用)存储在交易表本身中,作为浮动
  • 将货币存储在帐户表中
  • 交易金额将是一个DECIMAL(19,4)
  • 所有使用转换率的计算都将由我的应用程序处理,所以我控制舍入问题

我不认为浮动的转换率是一个问题,因为它主要是作为参考,我会把它转换成小数。

谢谢大家的宝贵意见。

如果你正在寻找一个通用的select,我build议DECIMAL(19, 4)是一个stream行的select(一个快速的谷歌certificate了这一点)。 我认为这起源于旧的VBA / Access / Jet货币数据types,是语言中的第一个定点小数types; 在VB6 / VBA6 / Jet 4.0中, Decimal只有“1.0版本”风格(即没有完全实现)。

存储定点十进制值的经验法则是至less存储一个小数位数,而不是实际需要的四舍五入。 将前端的旧Currencytypes映射到后端的DECIMAL(19, 4)types的原因之一是Currency展示了银行家自然界的四舍五入,而DECIMAL(p, s)通过截断舍入。

对于DECIMAL ,存储中的一个额外的小数位可以实现一个自定义舍入algorithm,而不是采取供应商的默认值(至less对于devise者来说,银行家的四舍五入是令人震惊的,因为devise者期望所有以.5结尾的值都是零)。

是的, DECIMAL(24, 8)听起来对我来说是过度的。 大多数货币报价为小数点后四位或五位。 我知道需要小数位数为8(或更多)的情况 ,但这是“正常”货币数量(比如四位小数)的比例,意味着小数精度应该相应地降低在这种情况下是浮点types)。 现在没有人有这么多钱要求24小数的精度:)

然而,一些研究可能是有条不紊的,而不是一个通用的方法。 请向您的devise师或领域专家了解可能适用的会计规则:GAAP,EU等。我依稀记得一些欧盟国家内部转移,明确规定四舍五入到小数点后五位,因此使用DECIMAL(p, 6)进行存储。 会计师一般似乎喜欢四位小数。


PS避免SQL Server的MONEY数据types,因为它在舍MONEY有严重的准确性问题,如便携性等其他考虑因素。请参阅Aaron Bertrand的博客 。


微软和语言devise师select了银行家的四舍五入,因为硬件devise师select了它[引用?]。 例如,它被包含在电气和电子工程师协会(IEEE)标准中。 硬件devise师select它是因为math家喜欢它。 参见维基百科 ; 解释:1906年版的“概率论与错误论”称之为“计算机规则”(“计算机”是指执行计算的人)。

我们最近实现了一个系统,需要处理多种货币的价值并在它们之间进行转换,并且艰难地想出了一些事情。

永远不要使用浮点数来赚钱

浮点algorithm引入了不准确的地方,直到他们搞砸了才可能被注意到。 所有的值都应该以整数或固定小数types存储,如果你select使用固定的十进制types,那么确保你完全理解这种types在底层使用什么(即,它在内部使用一个整数或浮点types)。

当你需要做计算或转换时:

  1. 将值转换为浮点
  2. 计算新的价值
  3. 四舍五入数字并将其转换回整数

在步骤3中将浮点数转换为整数时,请不要将其转换为数字 – 先使用math函数将其舍入。 这通常是round ,尽pipe在特殊情况下可以是floor或者ceil 。 知道区别并仔细select。

将值的types存储在值的旁边

如果您只处理一种货币,这对您来说可能并不重要,但这对于我们处理多种货币非常重要。 我们使用三字符代码作为货币,例如美元,英镑,日元,欧元等

根据具体情况,存储以下内容可能也会有帮助:

  • 这个数字是在税前还是在税后(以及税率是多less)
  • 数字是否是转换的结果(以及转换的结果)

知道你正在处理的数字的准确性界限

对于真实的价值,你想要像货币的最小单位一样精确。 这意味着你没有小于1分,1便士,1日元,分等的值。不要存储比无理由更高的准确性。

在内部,您可以select处理较小的值,在这种情况下,这是不同types的货币值 。 确保你的代码知道哪个是哪个,哪个不会混淆。 即使在这里也避免使用浮点值。


把所有这些规则加在一起,我们决定了下面的规则。 在运行代码中,货币使用最小单位的整数进行存储。

 class Currency { String code; // eg "USD" int value; // eg 2500 boolean converted; } class Price { Currency grossValue; Currency netValue; Tax taxRate; } 

在数据库中,值以stringforms存储在以下格式中:

 USD:2500 

那存储$ 25.00的价值。 我们之所以能做到这一点,只是因为处理货币的代码不需要在数据库层本身内,所以所有的值都可以先转换成内存。 其他情况无疑会适用于其他解决scheme。


如果我以前没有说清楚, 不要使用float!

小数点后4位会为您提供储存世界上最小的货币子单位的准确性。 如果您需要小额支付(纳米支付?!)准确度,您可以进一步减less。

我也喜欢DECIMAL DBMS特定的货币types,你更安全的应用程序IMO保持这种逻辑。 沿着同样的路线的另一种方法是简单地使用[long]整数,格式化为单元,以便在应用程序级别完成人类可读性(¤=货币符号)。

在MySQL中处理货币时,如果您知道货币值的精确度,请使用DECIMAL(13,2);如果您只需要一个足够快的近似值,请使用DOUBLE。 因此,如果您的应用程序需要处理高达1万亿美元(或欧元或英镑)的金钱价值,那么这应该工作:

 DECIMAL(13, 2) 

或者,如果您需要遵守GAAP,则使用:

 DECIMAL(13, 4) 

SQL Server上的money数据types在小数点后有四位数字。

从SQL Server 2000联机丛书:

货币数据代表积极或消极的金额。 在Microsoft®SQL Server™2000中,货币数据是使用货币和smallmoney数据types存储的。 货币数据可以存储到精确到小数点后四位。 使用货币数据types来存储值范围从-922,337,203,685,477.5808到+922,337,203,685,477.5807(需要8个字节来存储一个值)。 使用smallmoney数据types来存储从-214,748.3648到214,748.3647范围内的值(需要4个字节来存储值)。 如果需要更多的小数位数,请改用十进制数据types。

有时你需要去不到一分钱,有国际货币使用非常大的恶魔。 例如,您可能会向您的客户收取每笔交易0.088美分。 在我的Oracle数据库中,列被定义为NUMBER(20,4)

如果你要在数据库中进行任何types的算术运算(乘以计费率等等),那么你可能要比这里build议的人更精确,出于同样的原因,你永远不会希望在应用程序代码中使用小于双精度浮点值的任何值。

如果您正在使用IBM Informix Dynamic Server,那么您将拥有一个MONEYtypes,它是DECIMAL或NUMERICtypes上的一个小variables。 它总是一个定点types(而DECIMAL可以是一个浮点types)。 您可以指定从1到32的比例,以及从0到32的精度(默认为16,精度为2)。 因此,根据您需要存储的数据,您可以使用DECIMAL(16,2) – 仍然足够大以将美国联邦赤字保留到最接近的美分,或者您可以使用更小的范围或更多的小数位数。

这里有一个迟到的答案,但我用过

 DECIMAL(13,2) 

我正确的想法应该允许高达99,999,999,999.99。

我认为,在很大程度上,您或您的客户的要求应该决定使用何种精度和规模。 例如,对于我所处理的电子商务网站来说,只用英镑来处理,我被要求保留在十进制(6,2)。