你应该在SQL Server中selectMONEY还是DECIMAL(x,y)数据types?
我很好奇money
数据types和decimal(19,4)
(我相信这是钱在内部使用什么decimal(19,4)
之间是否有真正的差别。
我知道money
是特定于SQL Server的。 我想知道的是,如果有一个令人信服的理由,select一个在另一个之上; 大多数SQL Server示例(例如AdventureWorks数据库)使用money
而不是decimal
,例如价格信息。
我应该继续使用钱数据types,还是有利于使用小数? 钱是less字符input,但这不是一个有效的理由:)
永远不要使用金钱,这是不正确的,这是纯粹的垃圾,总是使用十进制/数字
运行这个来看看我的意思
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
SQLMenace说钱是不准确的。 但是你不能用钱来分配钱财! 3美元乘50美分多less钱? 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结果 --------------------- ----------------------------- ---------- 2949.8525 2949.8525
只要你不需要4位以上的十进制数字, money
就是好的,你要确保你的标量 – 不代表金钱。
我意识到,WayneM已经表明,他知道钱是特定于SQL Server的。 然而,他问是否有任何理由使用金钱超过十进制,反之亦然,我认为还有一个明显的原因应该说明,那就是使用十进制意味着如果你需要改变你的数据库pipe理系统 – 这可能发生。
让您的系统尽可能灵活!
如果你不知道你在做什么,一切都是危险的
即使高精度的小数types也不能保存一天:
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
types是整数
smallmoney
和decimal(10,4)
的文本表示可能看起来相似,但这并不能使它们互换。 当你看到存储为varchar(10)
date时,你是否畏缩? 这是一样的事情。
在幕后, money
/ smallmoney
只是一个bigint
/ int
。货币文本表示中的小数点是视觉上的绒毛,就像yyyy-mm-dddate中的破折号一样。 SQL实际上并不存储这些内部。
关于decimal
与money
,请select适合您的需求。 money
种类的存在是因为将会计价值存储为单位的1/10000的整数倍是非常普遍的。 另外,如果你正在处理实际的金钱和计算, 而不是简单的加减法, 那么你不应该在数据库级别这样做! 在应用程序层面使用支持Banker舍入(IEEE 754)的库,
好吧,我喜欢MONEY
! 这是一个比DECIMAL
便宜的字节,并且计算执行更快,因为(在下面)加法和减法操作本质上是整数运算。 @ SQLMenace的例子 – 这是一个很大的警告不知道 – 可以同样适用于INT
egers,其结果将为零。 但是, 在适当的情况下,没有理由不使用整数。
所以,当你正在处理的是MONEY
,并根据它所遵循的math规则(与INT
eger相同)来使用MONEY
时,它是完全“安全”和适当的。
如果SQL Server将MONEY
的划分和乘法分解为DECIMAL
(或FLOAT
?) – 可能会更好,但是他们没有select这样做; 他们也没有select将INT
egers分成FLOAT
。
MONEY
没有精确度问题; DECIMAL
在计算过程中使用的更大的中间types只是使用该types的一个“特征”(而且我实际上并不确定“特征”扩展到多远)。
回答具体的问题,一个“令人信服的理由”? 那么,如果你想SUM(x)
中的绝对最大性能,其中x
可以是DECIMAL
或MONEY
,那么MONEY
将具有边缘。
另外,不要忘记它是小表弟SMALLMONEY
只有4个字节,但最大值为214,748.3647
,这对于金钱来说是相当小的,所以通常并不适合。
为了certificate使用较大的中间types的问题,如果明确地将中间值赋给一个variables, 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
(好的,所以至lessDECIMAL
舍入而不是MONEY
截断 – 与整数相同)。
作为对其他答案的一般主旨的对立点。 看到金钱的许多好处…数据types! 在SQLCAT关系引擎指南中
具体我会指出以下几点
在客户实现方面,我们发现了一些关于货币数据types的有趣的性能数字。 例如,如果将Analysis Services设置为货币数据types(从double)以匹配SQL Server货币数据types,则处理速度(行/秒)有13%的提高。 为了在30分钟内在SQL Server集成服务(SSIS)中获得更快的性能,以便在30分钟内加载1.18TB,正如在SSIS 2008中所logging的那样 – 世界纪录ETL性能,观察到将四位小数(9,2) TPC-H LINEITEM表中的5个字节对金钱(8字节)的批量插入速度提高了20%。性能改进的原因是由于SQL Server的表格数据stream(TDS)协议,它具有关键的devise原理以紧凑的二进制forms传输数据,并尽可能接近SQL Server的内部存储格式。 从经验上看,这是在SSIS 2008期间观察到的 – 使用Kernrate进行的世界loggingETL性能testing; 当数据types从十进制转换为金钱时,协议显着下降。 这使得数据传输尽可能高效。 复杂的数据types需要额外的parsing和CPU周期来处理,而不是固定宽度的types。
所以这个问题的答案是“取决于”。 为了保持精确度,您需要对某些算术运算更加小心,但您可能会发现性能考虑使得这个值得。
我们刚刚遇到了一个非常类似的问题,现在我非常喜欢从未使用Money的+1,除非是顶级的演示。 我们有多个表格(实际上是销售凭证和销售发票),每个表格都包含一个或多个货币字段,我们需要按比例计算,以计算总发票税额与每个在销售凭证上。 我们的计算是
vat proportion = total invoice vat x (voucher line value / total invoice value)
这导致真实世界的货币/货币计算,导致分部的比例误差,然后乘以不正确的比例。 当这些数值随后被添加时,我们最终得到的总和不等于总发票价值。 如果括号中的任何一个数值都是小数(我将要把其中一个数字作为这样的数字),那么增加的数字就是正确的。
当括号不是最初用于工作的时候,我猜是因为涉及的数值越大,它就越有效地模拟更高的比例。 我们添加了括号,因为它是先进行乘法运算的,这在一些罕见的情况下会影响计算的准确度,但是现在却造成了这个更为常见的错误。
我想对MONEY和NUMERICAL有个不同的看法,主要是基于我自己的专业知识和经验。我的观点是MONEY,因为我用了很长时间,并且从来没有真正使用过NUMERICAL。
MONEY Pro:
- 原生数据types ,它使用与CPU寄存器(32或64位)相同的原生数据types( 整数 ),所以计算不需要不必要的额外开销,因此其更小和更快 ..货币需要8字节和数值(19,4)需要9字节(大12.5%)..只要用来表示金钱(作为金钱),速度有多快? 我对100万个简单的
SUM
testing数据显示,MONEY 275毫秒和NUMERIC 517毫秒..那几乎快了一倍 ..为什么SUMtesting呢? 看下一个专家点 - 最好的货币 ,最好的存款和运算,例如在会计,单个报告可以运行数百万加(SUM)和SUM操作完成后的几个乘法,对于非常大的会计应用几乎快两倍是非常重要的..
- 货币精度低 ,现实生活中的钱不一定非常精确,我的意思是很多人可能在乎1美分,但是0.01美分呢? 其实在我国银行不再关心分(昏迷后的数字),我不了解美国的银行或其他国家。
MONEY Con:
- 有限精度 MONEY只有4位数(昏迷后)的精度,所以它必须进行转换之前做分部操作。但是,然后再次金钱不需要如此精确,并不意味着被用来作为金钱不只是数字..
但是,大,但这里甚至是你的应用程序涉及真正的金钱,但不使用它在大量的SUM操作,如会计,并使用大量的分割和乘法,而不是你不应该使用金钱..
我find了一个关于精确度主题使用小数点以上的原因。
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
只要testing一下,然后做出决定。
我刚刚看到这个条目… http://thavash.spaces.live.com/blog/cns!CF6232111374DFD2!223.entry
基本上说,钱有一个精确的问题….
declare @m money declare @d decimal(9,2) set @m = 19.34 set @d = 19.34 select (@m/1000)*1000 select (@d/1000)*1000
对于金钱types,你会得到19.30而不是19.34。 我不知道是否有应用场景将钱分成1000部分进行计算,但这个例子确实暴露了一些限制。
戒
当您需要对数值进行乘法/除法时,您不应该使用金钱。 货币存储的方式与存储整数相同,而小数点存储为小数点和小数位。 这意味着在大多数情况下,金钱会降低准确性,而小数只有在转换回原来的比例时才会这样做。 钱是固定点,所以在计算过程中它的比例不会改变。 但是,因为当它作为十进制string打印时(而不是作为基本2string中的固定位置)打印时是固定点,所以精确地表示达到4的比例的值。 所以加法和减法,钱是好的。
小数点以10为底数表示,因此小数点的位置也以10为底数。 这就使得它的小数部分恰恰代表了它的价值,就像金钱一样。 不同的是,小数点的中间值可以保持高达38位的精度。
使用浮点数时,该值以二进制forms存储,就像它是一个整数一样,小数点(或二进制数)点的位置是相对于表示数字的位而言的。 由于它是一个二进制小数点,基数10的数字在小数点之后就会失去精度。 1/5或0.2,不能用这种方式精确表示。 金钱和小数都不受这个限制。
将货币转换为十进制很容易,执行计算,然后将结果值存回货币字段或variables。
从我的视angular来看,我想让数字发生的事情发生,而不必给他们太多的想法。 如果所有的计算都将被转换为十进制,那么对我来说,我只是想使用十进制。 为了显示目的,我会省钱。
在尺寸方面,我看不出有足够的差别来改变我的想法。 金钱需要4 – 8字节,而小数可以是5,9,13和17. 9个字节可以覆盖8字节的金钱可以的整个范围。 索引(比较和search应该是可比较的)。