Sql server 除法后十进制的Linq到SQL四舍五入
在计算两个度量单位之间的比率时,我遇到了一个精度问题 比率以计量单位表的形式存储在SQL Server数据库中,格式为:NumberOfDefaultUnits decimal(28,18) 在我的linqPad示例中,我有一个类来演示哪里出了问题Sql server 除法后十进制的Linq到SQL四舍五入,sql-server,linq,decimal,rounding,Sql Server,Linq,Decimal,Rounding,在计算两个度量单位之间的比率时,我遇到了一个精度问题 比率以计量单位表的形式存储在SQL Server数据库中,格式为:NumberOfDefaultUnits decimal(28,18) 在我的linqPad示例中,我有一个类来演示哪里出了问题 private class Test { public decimal saleUom { get; set; } public decimal piUom { get; set; } public decimal Ratio
private class Test
{
public decimal saleUom { get; set; }
public decimal piUom { get; set; }
public decimal RatioRight { get; set; }
public decimal RatioWrong { get; set; }
public decimal CalcledAlsoRight { get { return saleUom / piUom; } }
}
void Main()
{
}
结果是:
saleUom 453.592370000000000000
piUom 1000000.000000000000000000
RatioRight 0.000453592370000000000
RatioWrong 0.0004535923
CalcledAlsoRight 0.00045359237
花了一段时间才弄明白,必须将除数乘以1m才能得到正确的结果。如果把鞍数乘以1m,它会变得更奇怪。
结果是:
RatioRight = (sellUom * 1m) / (buyUom)
RatioRight 0.000453
我猜这与SQLServer如何存储十进制数(28,18)以及Linq如何转换divide命令有关
更新:所有值都是小数
更新2:
看起来这完全是SQL舍入的问题。从等式中删除.Net
select top 1 uom.NumberOfDefaultUnits
from UnitOfMeasures uom
where uom.Id = 13
select (select top 1 uom.NumberOfDefaultUnits
from UnitOfMeasures uom
where uom.Id = 13 )
/
(select top 1 uom.NumberOfDefaultUnits
from UnitOfMeasures uom
where uom.Id = 9)
第一个查询返回:453.5923700000000000
第二个:0.0004535923看起来SQL就是这样处理这些声明的十进制大小被彼此除的
DECLARE @p2 Decimal(28,18) = 1000000
DECLARE @p3 Decimal(28,18) = 453.59237
select @p3 / @p2
DECLARE @p1 Decimal(19,18) = 1 -- This is how Linq sends the * 1m
select @p3 / (@p2 *@p1)
select (@p3 *@p1) / @p2
结果:
0.0004535923
0.000453
0.00045359看起来SQL就是这样处理这些声明的十进制大小被彼此除的
DECLARE @p2 Decimal(28,18) = 1000000
DECLARE @p3 Decimal(28,18) = 453.59237
select @p3 / @p2
DECLARE @p1 Decimal(19,18) = 1 -- This is how Linq sends the * 1m
select @p3 / (@p2 *@p1)
select (@p3 *@p1) / @p2
结果:
0.0004535923
0.000453
0.00045359这肯定是由于SQL Server在计算中处理精度和比例的方式 如果将@mikeymouses示例更改为@p1使用6分制,则会得到一致的结果:
DECLARE @p2 Decimal(28,6) = 1000000
DECLARE @p3 Decimal(28,18) = 453.59237
select @p3 / @p2
DECLARE @p1 Decimal(19,18) = 1 -- This is how Linq sends the * 1m
select @p3 / (@p2 *@p1)
select (@p3 *@p1) / @p2
结果:
0.00045359237000000000000
0.00045359237000
0.000453592370000000000
精度和比例结果记录在上,但关键点是:
对于乘法:
- 结果精度=p1+p2+1
- 结果比例=s1+s2
- 结果精度=p1-s1+s2+max(6,s1+p2+1)
- 结果比例=最大值(6,s1+p2+1)
我认为这就是这里发生的事情。这肯定是由于SQL Server在计算中如何处理精度和规模 如果将@mikeymouses示例更改为@p1使用6分制,则会得到一致的结果:
DECLARE @p2 Decimal(28,6) = 1000000
DECLARE @p3 Decimal(28,18) = 453.59237
select @p3 / @p2
DECLARE @p1 Decimal(19,18) = 1 -- This is how Linq sends the * 1m
select @p3 / (@p2 *@p1)
select (@p3 *@p1) / @p2
结果:
0.00045359237000000000000
0.00045359237000
0.000453592370000000000
精度和比例结果记录在上,但关键点是:
对于乘法:
- 结果精度=p1+p2+1
- 结果比例=s1+s2
- 结果精度=p1-s1+s2+max(6,s1+p2+1)
- 结果比例=最大值(6,s1+p2+1)
我想这就是这里发生的事情。看起来
buyum
是一个整数。我敢打赌这一定与此有关。如果将其与1m
相乘,则会将其转换为十进制
。在这种情况下,我不确定小数除以整数的效果是什么。@Honeybager不,buyUom是一个小数。它直接来自计量单位表中的十进制(28,18)列。将添加一个屏幕快照您能看看buyum
的值是多少吗?它可能与分配给piUom
时的值不同(关于有效数字)。@honeybacker piUom的值是多少?在数据库中显示为“1000000.000000000000000000000000”。我不认为这是一个价值观问题。看看Calcledalsorlight酒店。它运行100%相同的东西“saleUom/piUom”,它得到了正确的答案,但发送到SQL的版本得到了错误的答案。我认为这与重要数字有关。NET中的一个十进制数有28-29个有效数字,在sql中,不管您定义它们的数量是多少,所以在您的例子中它将是18。这就是为什么我希望buyum
与piUom
具有不同数量的有效数字。当小数被除时,计算得到的精度和刻度。我不知道.NET是如何做到这一点的,但我相当确信您的问题是由此引起的。当您乘以1m
时,有效数字将再次设置为.NET默认值(28-29),这将改变结果的精度和比例。看起来buyUom
是一个整数。我敢打赌这一定与此有关。如果将其与1m
相乘,则会将其转换为十进制
。在这种情况下,我不确定小数除以整数的效果是什么。@Honeybager不,buyUom是一个小数。它直接来自计量单位表中的十进制(28,18)列。将添加一个屏幕快照您能看看buyum
的值是多少吗?它可能与分配给piUom
时的值不同(关于有效数字)。@honeybacker piUom的值是多少?在数据库中显示为“1000000.000000000000000000000000”。我不认为这是一个价值观问题。看看Calcledalsorlight酒店。它运行100%相同的东西“saleUom/piUom”,它得到了正确的答案,但发送到SQL的版本得到了错误的答案。我认为这与重要数字有关。NET中的一个十进制数有28-29个有效数字,在sql中,不管您定义它们的数量是多少,所以在您的例子中它将是18。这就是为什么我希望buyum
与piUom
具有不同数量的有效数字。当小数被除时,结果精度和sc