Sql server SQL Server总和和并集丢失十进制精度
这是一个与实体框架和SQL Server(2016)相关的问题 我注意到SQL server中有一些奇怪的行为,当以较低的比例和精度对十进制列求和,并将其与另一个具有较高比例和精度的十进制列合并时。结果值都具有较低的比例和精度 这似乎不正确,因为这表明在联合时,精度将被调整到适应它所需的最宽范围 这个例子很容易看出问题:Sql server SQL Server总和和并集丢失十进制精度,sql-server,entity-framework,Sql Server,Entity Framework,这是一个与实体框架和SQL Server(2016)相关的问题 我注意到SQL server中有一些奇怪的行为,当以较低的比例和精度对十进制列求和,并将其与另一个具有较高比例和精度的十进制列合并时。结果值都具有较低的比例和精度 这似乎不正确,因为这表明在联合时,精度将被调整到适应它所需的最宽范围 这个例子很容易看出问题: create table low_scale (val decimal(13,2)) create table high_scale (val decimal(19,8))
create table low_scale (val decimal(13,2))
create table high_scale (val decimal(19,8))
insert into low_scale values (10.00), (2.23)
insert into high_scale values (0.0000002), (2.02302023)
-- Query 1: Works fine - Result is at the widest precision required to accomodate the two types:
select * from low_scale
union all
select * from high_scale
-- Query 2: Strange - result is rounded to two decimal places:
select sum(val) from low_scale
union all
select sum(val) from high_scale
如您所料,查询1的结果是:
10.00000000
2.23000000
0.00000020
2.02302023
但是,这是查询2的结果:
12.23
2.02
似乎我可以通过首先将较低精度的柱铸造到较高精度来解决此问题,如下所示:
-- Result is at the expected 8 decimal places:
select sum(CAST(val as decimal(19,8))) from low_scale
union all
select sum(val) from high_scale
但是,我使用的是EntityFramework6,对生成的SQL没有太多控制权。在进行求和时,是否有任何方法强制实体框架转换到更高的精度,或者有其他方法来确保正确的行为
编辑:
我不知道为什么这会被标记为关于浮点的问题的重复。这与浮点无关—它使用的是十进制—一种定点数据类型。扩展Martin Smith在一篇评论中提到的内容,就是这样发生的: 从中,对一种类型的
十进制(p,s)
求和的结果总是十进制(38,s)
因此,联合的前半部分的输入是十进制(38,2)
,后半部分的输入是十进制(38,8)
表示联合时,结果精度为max(s1,s2)+max(p1-s1,p2-s2)
,刻度为max(s1,s2)
因此,将s1=2
,s2=8
,p1,p2=38
放入其中,我们得到了44的精度和8的刻度
然而,同一页指出,结果精度和比例的绝对最大值为38。当结果精度大于38时,相应的比例将减小,以防止结果的整数部分被截断
因此,它将刻度减少了6(将其降至2),使总精度降至38
这可以解释这种行为,但不能提供解决方案。
也就是说,有以下几种选择:
.Conact()
处理它,而不必担心SQL行为李>
.Conact()或.Union()之前,将Sum()
的结果强制转换为浮点或双精度。显然,这会带来一系列其他问题,但在某些情况下可能是可行的
在我的情况下,我可能会选择#2,因为肯定会有其他地方对这两个表进行汇总和合并,我不希望其他开发人员认识到他们会受到SQL server行为的影响(从EF的角度来看,我们正在处理.Net小数)。如何可能重复?这是关于定点数学的。这里没有什么是使用浮点数据类型,而是关于精度的损失,而不是使用浮点类型进行近似计算时可能会遇到的问题。不要担心,Tom,需要5个具有足够权限的成员才能将其标记为重复,因此前面的“可能”是。我在文章的顶部提出了一个建议:“在进行求和时,是否有任何方法可以强制实体框架转换到更高的精度,或者有其他方法来确保正确的行为?”因为您已经意识到使用最低精度时的SQL行为。
select SUM(val)从低刻度返回数据类型的结果数值(38,2)
从高刻度选择求和(val)
返回数据类型的结果数值(38,8)
如果将这两种数据类型合并在一起,SQL Server将选择数值(38,2)
啊,所以求和总是尽可能精确到38?我想它必须这样做,以允许潜在的数百万行被加在一起?