我很好奇货币数据类型和十进制(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份进行计算的应用场景,但这个示例确实暴露了一些局限性。
其他回答
永远不要使用金钱。它不精确,纯粹是垃圾;总是使用十进制/数字。
运行这个来看看我的意思:
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
我们刚刚遇到了一个非常相似的问题,我现在非常+1,因为除了在顶级演示中,我从不使用Money。我们有多个表(实际上是一个销售凭证和一个销售发票),由于历史原因,每个表都包含一个或多个Money字段,我们需要按比例计算出总发票中有多少Tax与销售凭证上的每一行相关。我们的计算是
vat proportion = total invoice vat x (voucher line value / total invoice value)
这将导致现实世界中的货币/货币计算,从而导致在分割部分上的刻度错误,然后乘以一个不正确的增值税比例。当这些价值随后相加时,我们最终得到的是增值税比例的总和,加起来不等于发票总价值。如果括号中的任何一个值是小数(我将把其中一个转换为小数),vat比例将是正确的。
当括号不存在的时候,原来这是工作的,我猜是因为涉及到更大的值,它有效地模拟了一个更高的规模。我们添加括号是因为它先做乘法运算,这在一些罕见的情况下会破坏计算的精度,但这现在已经导致了这个更常见的错误。
You shouldn't use money when you need to do multiplications / divisions on the value. Money is stored in the same way an integer is stored, whereas decimal is stored as a decimal point and decimal digits. This means that money will drop accuracy in most cases, while decimal will only do so when converted back to its original scale. Money is fixed point, so its scale doesn't change during calculations. However because it is fixed point when it gets printed as a decimal string (as opposed to as a fixed position in a base 2 string), values up to the scale of 4 are represented exactly. So for addition and subtraction, money is fine.
小数点内部以10为底表示,因此小数点的位置也以10为底数为基础。这使得它的小数部分准确地代表了它的值,就像货币一样。不同之处在于十进制的中间值可以保持38位的精度。
对于浮点数,值以二进制形式存储,就像它是一个整数一样,并且小数点(或二进制,嗯,)点的位置相对于表示该数字的位。因为它是一个二进制小数点,以10为基数的数字在小数点后失去精度。1/5,或0.2,不能用这种方式精确地表示。货币和十进制都不受这个限制。
将货币转换为十进制,执行计算,然后将结果值存储回货币字段或变量中,这非常简单。
从我的角度来看,我希望发生在数字上的事情不需要太多思考就能发生。如果所有的计算都要转换成十进制,那么对我来说,我只想用十进制。我会保留money字段用于显示。
就尺寸而言,我看不出有多大差别来改变我的想法。Money需要4 - 8个字节,而decimal可以是5、9、13和17。9个字节可以覆盖8个字节的货币所能覆盖的全部范围。索引方面(比较和搜索应该具有可比性)。
我找到了在精确度科目中使用十进制而不是货币的原因。
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
只需测试一下,然后做出决定。
我刚看到这个博客: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份进行计算的应用场景,但这个示例确实暴露了一些局限性。