当前位置:  开发笔记 > 数据库 > 正文

您应该在SQL Server中选择MONEY或DECIMAL(x,y)数据类型吗?

如何解决《您应该在SQLServer中选择MONEY或DECIMAL(x,y)数据类型吗?》经验,为你挑选了8个好方法。

我很好奇money数据类型和类似之间是否存在真正的差异decimal(19,4)(我认为这是内部使用的钱).

我知道这money是特定于SQL Server的.我想知道是否有令人信服的理由选择一个而不是另一个; 大多数SQL Server示例(例如AdventureWorks数据库)使用money而不是decimal价格信息之类的东西.

我应该继续使用money数据类型,还是使用十进制代替?Money输入的字符较少,但这不是有效的原因:)



1> SQLMenace..:

你永远不应该用钱.它不精确,是纯垃圾; 总是使用十进制/数字.

运行这个看看我的意思:

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"对于将结果投射到该类型以便以文化敏感的方式显示给用户非常有用,但是你认为用于计算本身非常糟糕.
除了"钱"之外,"钱"的乘法和除法,这个"插图"是操纵性的.有记录的事实是,"钱"具有固定且非常有限的精度.在这种情况下,首先应该乘以,然后除以.在此示例中更改运算符的顺序,您将得到相同的结果.一个`money`本质上是一个64位的int,如果你要处理整数,你会在分割之前成倍增加.
你的例子没有意义,因为没有人会将两个类型的金钱对象相乘.如果你想证明自己的观点,你需要比较一个小数乘以小数乘以​​小数乘以​​小数.
..但仍然令人费解的是为什么钱*钱没有钱的精确度.
@Learning:确实有钱.但是,您仍然会遇到可能随时间累积的舍入错误.十进制类型不使用二进制算法:它保证它在纸上完成相同的基础10结果.
我认为双方都有好的观点.我从中获取的将是继续使用小数,但我偶尔会使用Money来显示.
再看一遍,他们都是错的。如果您将步长降低,则Decimal在2950处正确。这是因为它正确地将中间步长从0.8525向上舍入,而将金钱向下舍入。因此正确答案应该是2950,而不是2949或2949.8525。
-1因为"纯垃圾"是一种主观判断.但主要是因为@configurator提供的答案.
我认为他们将使用PC上设置的区域值,所以它可以在美国PC上获得50美元,在没有任何特殊转换过程的情况下在法国PC上获得50欧元.所以我决定使用十进制作为准确和可维护的类型.请阅读我的帖子关于十进制类型的准确性的其他原因.

2> configurator..:

SQLMenace表示资金不准确.但是你不要用钱来分钱/分钱!3美元乘50美分多少钱?150美元?你用标量乘以/除以钱,这应该是十进制的.

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

money只要您不需要超过4位十进制数字就可以了,并且确保您的标量 - 不代表金钱 - 是decimal.


一美元钞票可以获得多少1美分的硬币?对此的回答需要金钱/金钱.
@Learning在这种情况下,结果不是钱,而是浮动.(基本尺寸分析.)
@mson他是正确的,不要像你用一行评论那样做个人批评,这没有用.如果他没有除以0.01美元而是0.01,那么结果是100美元而不是100美元.一美元100美分,而不是100美分.单位很重要!绝对是潜水的好地方,也许是金钱的倍增.
如果我想花1000美元购买价格为36美元的股票,这不是"钱/钱"的合法用法吗?答案是整个单位没有附上美元符号,这是正确的!这是一个非常合理的场景,暗示由于像这样的奇怪边缘情况,`money`不是一个好的数据类型,因为结果总是被截断回来适合`money`而不是遵循正常的精度规则和规模.如果你想计算一组'money`值的标准偏差怎么办?是的,`Sqrt(Sum(money*money))`(简化)实际上确实有意义.
@Learning:你问数据库一美元多少美分?无论如何,这将返回正确的结果.他的问题是钱/钱只精确到四位数(它是0.2949),然后当乘以10000它变成2949.0000.
@learning你的评论表明你不懂科学和转换.如果你确实需要计算一美元钞票给你多少1美分的硬币,你不会除以1美分,而是除以精确的转换.在这种情况下的转换是准确的,并不以任何方式支持您的意图.
那么我可以用什么比特币?
@PanagiotisKanavos人们很容易认为你是用汇率划分货币,但它仍然是货币的数量.汇率本身仍然是标量,而不是金钱.我同意这种钱类型足够混乱,以避免在可能的情况下使用.
这基本上只是说“可以得到错误的答案,因为在技术上语义上奇数的计算中它只会得到错误的答案”。好的,但是还是错了。为什么不使用即使在语义上奇怪的情况下也不会出错的类型?(换句话说,“优势”是什么?)

3> Anon..:

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

即使是高精度的十进制类型也无法节省一天:

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


money类型是整数

文本表示smallmoneydecimal(10,4)可能看起来相似,但这并不能使它们互换.当你看到日期存储为时,你会畏缩varchar(10)吗?这是一回事.

在幕后,money/ smallmoney只是一个bigint/ int 文本表示中的小数点money是视觉绒毛,就像yyyy-mm-dd日期中的破折号一样.SQL实际上并不在内部存储它们.

关于decimalvs money,选择适合您需求的任何内容.的money存在类型,因为储存计费值作为单位的1 /第一万整数倍是很常见的.此外,如果您正在处理除简单加法和减法之外的实际金钱和计算,您不应该在数据库级别执行此操作! 使用支持Banker Rounding(IEEE 754)的库在应用程序级别执行此操作


规模溢出.在小尺度上,数字(a,b)*数字(c,d)产生数字(a-b + c-d + 1,max(b,d)).但是,如果(a + b + c + d)> 38,则SQL会限制比例,从分数侧抢夺精度以填充整数侧,从而导致舍入误差.
我认为这是最具启发性的答案,因为你不仅仅解释了传播的错误,而且解释了场景背后的真实情况,以及为什么MONEY首先存在.我不确定为什么花了4年时间才能得到这个答案,但也许是因为太多关注计算"问题",而不是关注金钱与小数的原因和方法.

4> Dean..:

我意识到WayneM已经声明他知道钱是特定于SQL Server的.但是,他问是否有任何理由使用小数点数或反之亦然,我认为仍然应该说明一个明显的原因并且使用小数意味着如果你不得不改变你的DBMS,那就更少担心了 - 这可能发生.

使您的系统尽可能灵活!



5> dsz..:

好吧,我喜欢MONEY!它比一个字节便宜DECIMAL,并且计算执行得更快,因为(在封面下)加法和减法操作基本上是整数运算.@ SQLMenace的例子 - 对于不知道的人来说是一个很好的警告 - 同样可以应用于INTegers,结果为零.但是,没有理由不在适当的地方使用整数.

因此,MONEY当您正在处理的内容是MONEY根据其遵循的数学规则(与INTeger 相同)使用时,它非常"安全"且适合使用.

如果SQL Server提升MONEYs 和DECIMALs(或FLOATs?)的分割和乘法会更好- 可能,但他们没有选择这样做; 他们也没有选择在分裂时促进INT艾格斯FLOAT.

MONEY没有精确问题; 那DECIMAL得面对具有计算过程中使用较大的中间类型仅仅是使用该类型的"功能"(我不肯定实际上多远,即"功能"延伸).

回答具体问题,一个"令人信服的理由"?好吧,如果你想在一个或两个SUM(x)地方绝对最大的表现,那么就会有优势.xDECIMALMONEYMONEY

另外,不要忘记它是一个较小的堂兄,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截断 - 与整数相同.)


`MONEY`比一个*大*`DECIMAL`少一个字节,精度高达19位.但是,大多数现实世界的货币计算(高达9.99美元)都可以装入`DECIMAL(9,2)`,这只需要5个字节.您可以节省大小,减少对舍入错误的担忧,*和*使您的代码更具可移植性.
@JonofAllTrades是一个很好的观点.

6> 小智..:

我们刚刚遇到了一个非常类似的问题,我现在非常喜欢+1,因为除了顶层演示之外从不使用Money.我们有多个表(实际上是销售凭证和销售发票),其中每个表都包含一个或多个货币字段,这是出于历史原因,我们需要按比例计算以计算总发票税与每个税额的相关程度.销售凭证上的行.我们的计算是

vat proportion = total invoice vat x (voucher line value / total invoice value)

这导致现实世界的货币/货币计算导致分割部分的尺度误差,然后乘以不正确的增量比例.当随后添加这些值时,我们最终得到的桶数比例总和不会与总发票金额相加.如果括号中的任何一个值都是小数(我即将投出其中一个),那么增值比例就是正确的.

当括号不存在时,原来这个用来工作,我想因为涉及的值越大,它就能有效地模拟更高的尺度.我们添加了括号,因为它首先进行乘法运算,这在极少数情况下会超出可用于计算的精度,但现在这已经导致了这个更常见的错误.


但它只是这样做,因为一个无知的开发人员忽略了增值税计算的规则和记录的货币精确限制.

7> Martin Smith..:

作为对抗其他答案的一般主旨的对立点.查看货币的许多好处......数据类型!在SQLCAT的关系引擎指南中

具体来说,我会指出以下内容

在客户实施方面,我们发现了一些有关货币数据类型的有趣性能数据.例如,当Analysis Services设置为货币数据类型(来自double)以匹配SQL Server货币数据类型时,处理速度(行/秒)提高了13%.为了在SQL Server Integration Services(SSIS)中获得更快的性能,在30分钟内加载1.18 TB,如SSIS 2008中所述 - 世界记录ETL性能,观察到更改四个小数(9,2)列的大小为在TPC-H LINEITEM表中5个字节到钱(8个字节),批量插入速度提高了20%......性能提升的原因是因为SQL Server的表格数据流(TDS)协议,它具有以紧凑二进制形式传输数据并尽可能接近SQL Server内部存储格式的关键设计原则.根据经验,这在SSIS 2008期间观察到 - 使用Kernrate的世界纪录ETL性能测试; 当数据类型从十进制转换为货币时,协议显着下降.这使得数据传输尽可能高效.复杂数据类型需要额外的解析和CPU周期来处理,而不是固定宽度类型.

所以问题的答案是"它取决于".您需要对某些算术运算更加小心以保持精度,但您可能会发现性能方面的考虑使其值得.



8> 小智..:

我想对MONEY与NUMERICAL给出不同的看法,主要基于我自己的专业知识和经验...我的观点是MONEY,因为我已经使用了很长时间并且从未真正使用过NUMERICAL ... .

MONEY Pro:

原生数据类型.它使用一个本地数据类型(整数)作为相同的CPU寄存器(32位或64位),所以计算不需要不必要的开销所以它的更小更快 ... MONEY需要8个字节和数值(19,4 )需要9个字节(大12.5%)......

只要它用于它(因为钱),MONEY就会更快.多快?我SUM对100万个数据的简单测试表明,MONEY是275毫秒,NUMERIC是517毫秒...这几乎快两倍 ...为什么SUM测试?见下一个Pro

最物有所值.MONEY最适合存储资金并进行操作,例如会计.在SUM操作完成后,单个报告可以运行数百万个添加(SUM)和一些乘法.对于非常大的会计应用,它几乎快两倍,而且非常重要......

低精度的钱.现实生活中的金钱不需要非常精确.我的意思是,很多人可能只关心1美分,但是0.01美元怎么样呢?事实上,在我的国家,银行不再关心美分(小数点后的数字); 我不知道美国银行或其他国家......

钱币:

精度有限.MONEY只有四位数(在逗号之后)精度,所以在进行除法之类的操作之前必须进行转换......但是再次money不需要那么精确并且意味着要用作钱,而不仅仅是数...

但是......大,但这里甚至你的应用程序涉及真钱,但不要在很多SUM操作中使用它,比如会计.如果你使用大量的除法和乘法,那么你不应该使用MONEY ......


@HaakonLøtveit这个完整的Q&A线程是关于SQL Server数据类型的"钱",所以我认为他们不需要在答案中指明这一点.在某些情况下(例如加载数据),金钱可以比使用十进制更快,有关详细信息,请参阅Martin Smith的答案.我同意这个答案的大部分内容,因为某些用例可能使Money比十进制更有效,但是除非有一个非常令人信服的使用它的情况,我认为应该避免.
推荐阅读
凹凸曼00威威_694
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有