我很好奇货币数据类型和十进制(19,4)之类的数据类型之间是否有真正的区别(我相信这是货币内部使用的)。

我知道钱是特定于SQL Server的。我想知道是否有令人信服的理由来选择一个而不是另一个;大多数SQL Server样本(例如AdventureWorks数据库)使用金钱而不是小数来表示价格信息。

我是否应该继续使用货币数据类型,或者使用十进制是否有好处?金钱可以输入的字符更少,但这不是一个有效的理由:)


当前回答

SQLMenace说钱是不精确的。但是你不能把钱乘以/除以钱!3美元乘以50美分等于多少?150 dollarcents ?你用标量乘(除)钱,结果应该是小数。

DECLARE
@mon1 MONEY,
@mon4 MONEY,
@num1 DECIMAL(19,4),
@num2 DECIMAL(19,4),
@num3 DECIMAL(19,4),
@num4 DECIMAL(19,4)

SELECT
@mon1 = 100,
@num1 = 100, @num2 = 339, @num3 = 10000

SET @mon4 = @mon1/@num2*@num3
SET @num4 = @num1/@num2*@num3

SELECT @mon4 AS moneyresult,
@num4 AS numericresult

结果在正确的结果:

moneyresult           numericresult
--------------------- ---------------------------------------
2949.8525             2949.8525

钱是好的,只要你不需要超过4个十进制数字,你要确保你的标量(不代表钱)是小数。

其他回答

我找到了在精确度科目中使用十进制而不是货币的原因。

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

只需测试一下,然后做出决定。

我喜欢钱!它比DECIMAL少一个字节,而且计算执行得更快,因为(实际上)加法和减法操作本质上是整数操作。@SQLMenace的例子——这对不了解情况的人是一个很大的警告——同样可以应用于整数,其结果将为零。但这并不是不使用整数的理由——在适当的地方。

所以,当你处理的是金钱,并根据它遵循的数学规则(与整数相同)使用金钱时,使用金钱是完全“安全”和适当的。

如果SQL Server将MONEY的除法和乘法转换为小数(或浮点数?)会更好吗?可能,但他们没有选择这样做;在除法时,他们也没有选择将整数提升为浮点数。

金钱没有精确度问题;小数在计算过程中使用更大的中间类型只是使用该类型的一个“特征”(我实际上不确定这个“特征”延伸了多远)。

要回答具体的问题,一个“令人信服的理由”?好吧,如果你想在SUM(x)中获得绝对最大性能,其中x可以是DECIMAL或MONEY,那么MONEY将具有优势。

另外,不要忘记它的小表兄弟smallmoney——只有4个字节,但它的最大值为214,748.3647——这对于钱来说非常小——因此通常不适合。

为了证明使用更大的中间类型的观点,如果你显式地将中间类型赋值给一个变量,DECIMAL也会遇到同样的问题:

declare @a decimal(19,4)
declare @b decimal(19,4)
declare @c decimal(19,4)
declare @d decimal(19,4)

select @a = 100, @b = 339, @c = 10000

set @d = @a/@b

set @d = @d*@c

select @d

产生2950.0000(好吧,至少是DECIMAL四舍五入,而不是MONEY截断——与整数相同。)

如果你不知道自己在做什么,一切都是危险的

即使是高精度的十进制类型也无法扭转局面:

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)

之前所有的帖子都提出了有效的观点,但有些并没有准确地回答这个问题。

问题是:当我们已经知道钱是一种不那么精确的数据类型,并且在复杂的计算中使用它会导致错误时,为什么有人更喜欢钱?

当你不需要进行复杂的计算,并且可以用这种精度来换取其他需求时,你就会使用金钱。

例如,当您不需要进行这些计算,而需要从有效的货币文本字符串中导入数据时。此自动转换仅适用于MONEY数据类型:

SELECT CONVERT(MONEY, '$1,000.68')

我知道你可以制作自己的导入程序。但有时您不希望使用全球特定的区域设置格式重新创建导入例程。

另一个例子,当你不需要进行这些计算(你只需要存储一个值),需要节省1个字节(金钱需要8个字节,而十进制(19,4)需要9个字节)。在一些应用中(快速CPU,大内存,慢IO),比如只是读取大量的数据,这也可以更快。

我意识到WayneM已经声明他知道钱是特定的SQL Server。然而,他问是否有任何理由使用货币而不是十进制,反之亦然,我认为一个明显的原因仍然应该说明,那就是使用十进制意味着如果你不得不改变你的DBMS,它可以减少一件担心的事情——这是可能发生的。

使您的系统尽可能灵活!