我很好奇货币数据类型和十进制(19,4)之类的数据类型之间是否有真正的区别(我相信这是货币内部使用的)。
我知道钱是特定于SQL Server的。我想知道是否有令人信服的理由来选择一个而不是另一个;大多数SQL Server样本(例如AdventureWorks数据库)使用金钱而不是小数来表示价格信息。
我是否应该继续使用货币数据类型,或者使用十进制是否有好处?金钱可以输入的字符更少,但这不是一个有效的理由:)
我很好奇货币数据类型和十进制(19,4)之类的数据类型之间是否有真正的区别(我相信这是货币内部使用的)。
我知道钱是特定于SQL Server的。我想知道是否有令人信服的理由来选择一个而不是另一个;大多数SQL Server样本(例如AdventureWorks数据库)使用金钱而不是小数来表示价格信息。
我是否应该继续使用货币数据类型,或者使用十进制是否有好处?金钱可以输入的字符更少,但这不是一个有效的理由:)
当前回答
我刚看到这个博客:SQL Server中的金钱vs.十进制。
这基本上是说金钱有一个精确的问题……
declare @m money
declare @d decimal(9,2)
set @m = 19.34
set @d = 19.34
select (@m/1000)*1000
select (@d/1000)*1000
对于货币类型,你将得到19.30而不是19.34。我不确定是否存在将钱分成1000份进行计算的应用场景,但这个示例确实暴露了一些局限性。
其他回答
我们刚刚遇到了一个非常相似的问题,我现在非常+1,因为除了在顶级演示中,我从不使用Money。我们有多个表(实际上是一个销售凭证和一个销售发票),由于历史原因,每个表都包含一个或多个Money字段,我们需要按比例计算出总发票中有多少Tax与销售凭证上的每一行相关。我们的计算是
vat proportion = total invoice vat x (voucher line value / total invoice value)
这将导致现实世界中的货币/货币计算,从而导致在分割部分上的刻度错误,然后乘以一个不正确的增值税比例。当这些价值随后相加时,我们最终得到的是增值税比例的总和,加起来不等于发票总价值。如果括号中的任何一个值是小数(我将把其中一个转换为小数),vat比例将是正确的。
当括号不存在的时候,原来这是工作的,我猜是因为涉及到更大的值,它有效地模拟了一个更高的规模。我们添加括号是因为它先做乘法运算,这在一些罕见的情况下会破坏计算的精度,但这现在已经导致了这个更常见的错误。
永远不要使用金钱。它不精确,纯粹是垃圾;总是使用十进制/数字。
运行这个来看看我的意思:
DECLARE
@mon1 MONEY,
@mon2 MONEY,
@mon3 MONEY,
@mon4 MONEY,
@num1 DECIMAL(19,4),
@num2 DECIMAL(19,4),
@num3 DECIMAL(19,4),
@num4 DECIMAL(19,4)
SELECT
@mon1 = 100, @mon2 = 339, @mon3 = 10000,
@num1 = 100, @num2 = 339, @num3 = 10000
SET @mon4 = @mon1/@mon2*@mon3
SET @num4 = @num1/@num2*@num3
SELECT @mon4 AS moneyresult,
@num4 AS numericresult
输出:2949.0000 2949.8525
有些人说钱不能一分一分
这是我计算相关性的一个问题,把它换成金钱会得到错误的结果。
select t1.index_id,t2.index_id,(avg(t1.monret*t2.monret)
-(avg(t1.monret) * avg(t2.monret)))
/((sqrt(avg(square(t1.monret)) - square(avg(t1.monret))))
*(sqrt(avg(square(t2.monret)) - square(avg(t2.monret))))),
current_timestamp,@MaxDate
from Table1 t1 join Table1 t2 on t1.Date = traDate
group by t1.index_id,t2.index_id
之前所有的帖子都提出了有效的观点,但有些并没有准确地回答这个问题。
问题是:当我们已经知道钱是一种不那么精确的数据类型,并且在复杂的计算中使用它会导致错误时,为什么有人更喜欢钱?
当你不需要进行复杂的计算,并且可以用这种精度来换取其他需求时,你就会使用金钱。
例如,当您不需要进行这些计算,而需要从有效的货币文本字符串中导入数据时。此自动转换仅适用于MONEY数据类型:
SELECT CONVERT(MONEY, '$1,000.68')
我知道你可以制作自己的导入程序。但有时您不希望使用全球特定的区域设置格式重新创建导入例程。
另一个例子,当你不需要进行这些计算(你只需要存储一个值),需要节省1个字节(金钱需要8个字节,而十进制(19,4)需要9个字节)。在一些应用中(快速CPU,大内存,慢IO),比如只是读取大量的数据,这也可以更快。
我找到了在精确度科目中使用十进制而不是货币的原因。
DECLARE @dOne DECIMAL(19,4),
@dThree DECIMAL(19,4),
@mOne MONEY,
@mThree MONEY,
@fOne FLOAT,
@fThree FLOAT
SELECT @dOne = 1,
@dThree = 3,
@mOne = 1,
@mThree = 3,
@fOne = 1,
@fThree = 3
SELECT (@dOne/@dThree)*@dThree AS DecimalResult,
(@mOne/@mThree)*@mThree AS MoneyResult,
(@fOne/@fThree)*@fThree AS FloatResult
十进制结果 > 1.000000
MoneyResult > 0.9999
FloatResult > 1
只需测试一下,然后做出决定。
如果你不知道自己在做什么,一切都是危险的
即使是高精度的十进制类型也无法扭转局面:
declare @num1 numeric(38,22)
declare @num2 numeric(38,22)
set @num1 = .0000006
set @num2 = 1.0
select @num1 * @num2 * 1000000
1.000000 <-应该是0.6000000
货币类型是整数
smallmoney和decimal(10,4)的文本表示可能看起来很像,但这并不意味着它们可以互换。当您看到日期存储为varchar(10)时,您会感到畏缩吗?这是一样的。
在幕后,money/smallmoney只是一个bigint/int。money的文本表示中的小数点在视觉上是无用的,就像yyyy-mm-dd日期中的破折号。SQL实际上并没有在内部存储这些数据。
关于十进制和金钱,选择任何适合你需要的。货币类型的存在是因为将会计值存储为单位的1/ 10000000的整数倍数是非常常见的。此外,如果您正在处理实际的货币和计算,而不仅仅是简单的加减法,那么您不应该在数据库级别上这样做!在应用程序级别使用支持Banker's舍入的库进行计算(IEEE 754)