我使用一个十进制列在数据库中存储货币值,今天我想知道要使用什么样的精度和比例。
既然假定固定宽度的字符列更有效率,我认为十进制列也可以这样。是吗?
我应该使用什么样的精度和规模? 我想的是24/8精度。这是过度杀伤,还是不够还是可以?
我决定这么做:
DECIMAL(19,4)
我不认为转换率的浮点数是一个问题,因为它主要是作为参考,而且无论如何我将把它转换为小数。
谢谢你们的宝贵意见。
SQLServer 上的货币数据类型在小数后面有四位数字。
来自 SQLServer2000联机丛书:
货币数据代表正数或负数的货币数额。在 MicrosoftSQLServerTM 2000中,货币数据使用货币和小额货币数据类型存储。货币数据的存储精度可达小数点后四位。使用 money 数据类型将值存储在从 -922,337,203,685,477.5808到 + 922,337,203,685,477.5807的范围内(存储值需要8个字节)。使用 smallmoney 数据类型将值存储在 -214,748.3648到214,748.3647之间(存储值需要4个字节)。如果需要更多的小数位,则改为使用十进制数据类型。
如果您使用的是 IBM Informix Dynamic Server,那么您将拥有一个 MONEY 类型,它是 DECIMAL 或 NUMERIC 类型的次要变体。它始终是定点类型(而 DECIMAL 可以是浮点类型)。您可以指定从1到32的刻度,以及从0到32的精度(默认为刻度为16,精度为2)。因此,根据你需要存储的数据,你可以使用 DECIMAL (16,2)——仍然足以将美国联邦赤字保持在最接近1美分的水平——或者你可以使用一个更小的范围,或者更多的小数位。
有时你需要去不到一分钱,有国际货币使用非常大的妖魔化。例如,您可能在每次交易中向客户收取0.088美分。在我的 Oracle 数据库中,列被定义为 NUMBER (20,4)
我认为,在很大程度上,您或您的客户的需求应该决定使用的精度和规模。例如,对于电子商务网站,我正在处理的钱只有英镑,我已经被要求保持它的十进制(6,2)。
如果你正在寻找一个一刀切的尺寸,我建议 DECIMAL(19, 4)是一个流行的选择(快速谷歌证明了这一点)。我认为这源于旧的 VBA/Access/Jet Currency 数据类型,它是语言中的第一个定点小数类型; Decimal只是在 VB6/VBA6/Jet 4.0中以‘ version 1.0’风格(即未完全实现)出现。
DECIMAL(19, 4)
Decimal
对于定点小数值的 储藏室,经验法则是至少存储一个小数位,而这个小数位是允许四舍五入的。将前端的旧 Currency类型映射到后端的 DECIMAL(19, 4)类型的原因之一是,Currency表现出银行家的舍入性质,而 DECIMAL(p, s)则表现出截断舍入性质。
Currency
DECIMAL(p, s)
在 DECIMAL的存储空间中增加一个小数点后的位置,可以实现自定义舍入算法,而不是采用供应商的默认值(至少可以说,对于一个期望所有以.5结尾的值从零舍入的设计者来说,银行家的舍入是令人担忧的)。
DECIMAL
是的,我觉得 DECIMAL(24, 8)听起来有点过了。大多数货币的报价为小数点后四或五位。我知道有些情况需要一个8(或更多)的小数位 是,但这是一个“正常”的货币量(比如说四个小数位)已经按比例分配,这意味着小数精度应该相应降低(也考虑在这种情况下浮点类型)。如今,没有人有那么多钱来要求精度达到小数点后24位:)
DECIMAL(24, 8)
然而,一些研究可能是合适的,而不是一刀切的方法。向您的设计师或领域专家询问可能适用的会计准则: GAAP、 EU 等。我依稀记得一些欧盟国家之间的转账,它们有四舍五入到小数点后五位的明确规则,因此使用 DECIMAL(p, 6)进行存储。会计师通常倾向于小数点后四位。
DECIMAL(p, 6)
PS 避免使用 SQL Server 的 MONEY数据类型,因为它在舍入时存在严重的准确性问题,其他考虑因素包括可移植性等。见 Aaron Bertrand 的博客。
MONEY
微软和语言设计者之所以选择银行家舍入,是因为硬件设计者选择了它[引用? ].例如,它被载入美国电气与电子工程师协会(IEEE)标准。硬件设计者选择它是因为数学家更喜欢它。参见 维基百科; 转述: 1906年版的概率和错误理论称这为“计算机的规则”(“计算机”意味着人类执行计算)。
小数点后4位可以精确地存储世界上最小的货币子单位。如果你需要小额支付(纳米支付? !) ,你可以进一步降低准确性。
相对于特定于 DBMS 的货币类型,我也更喜欢 DECIMAL,在 IMO 应用程序中保持这种逻辑更安全。同样的另一种方法是简单地使用[ long ]整数,在应用程序级别将其格式化为 unit.subunit,以提高人们的可读性(= 货币符号)。
如果你要在数据库中进行任何类型的算术运算(乘以计费率等) ,你可能需要比这里的人建议的更高的精度,出于同样的原因,你永远不会想在应用程序代码中使用任何低于双精度浮点值。
我们最近实现了一个系统,该系统需要处理多种货币的价值并在它们之间进行转换,并通过艰难的方式解决了一些问题。
永远不要用浮点数来换钱
浮点数算法会引入一些不准确的地方,这些地方在他们搞砸某些事情之前可能不会被注意到。所有的值应该存储为整数或固定小数类型,如果你选择使用固定小数类型,然后确保你准确地理解该类型在底层做什么(即,它内部使用整数或浮点类型)。
当需要进行计算或转换时:
在步骤3中,当将一个浮点数转换回一个整数时,不要只是强制转换它——首先使用一个数学函数对它进行四舍五入。这通常是 round,虽然在特殊情况下它可能是 floor或 ceil。知道区别,仔细选择。
round
floor
ceil
将数字的类型存储在值旁边
如果你只处理一种货币,这对你来说可能没有那么重要,但对我们处理多种货币来说却很重要。我们使用3个字符的代码表示货币,如美元、英镑、日元、欧元等。
根据具体情况,存储以下信息可能也有帮助:
知道你要处理的数字的准确界限
对于实际值,您希望精确到货币的最小单位。这意味着你没有小于一分钱、一分钱、一日元、一分钱等的价值。不要无缘无故地存储比那个精度更高的值。
在内部,您可以选择处理较小的值,在这种情况下,这是 不同类型的货币价值。确保您的代码知道哪些是哪些,并且不要将它们混淆。即使在这里也要避免使用浮点值。
将所有这些规则加在一起,我们决定采用以下规则。在运行代码中,货币使用最小单位的整数存储。
class Currency { String code; // eg "USD" int value; // eg 2500 boolean converted; } class Price { Currency grossValue; Currency netValue; Tax taxRate; }
在数据库中,这些值以下列格式存储为字符串:
USD:2500
存储的价值是25美元。我们之所以能够做到这一点,仅仅是因为处理货币的代码不需要位于数据库层本身,所以所有的值都可以首先转换为内存。其他情况无疑会导致其他解决方案。
以防我之前没说清楚 别用浮子!
在使用 MySQL 处理货币时,如果你知道货币值的精确度,可以使用 DECIMAL (13,2) ; 如果你只是想要一个快速、足够好的 Circa,可以使用 DOUble。 因此,如果您的应用程序需要处理高达1万亿美元(或欧元或英镑)的货币价值,那么这应该可以工作:
DECIMAL(13, 2)
或者,如果你需要遵守 公认会计原则,那么使用:
DECIMAL(13, 4)
这个回答有点晚,不过我已经用过了
DECIMAL(13,2)
我觉得应该可以达到99.999.999.999.99。