这是一个与Entity Framework和SQL Server(2016)相关的问题。
我在SQL服务器中发现了一些奇怪的行为,当将小数列与较低的比例和精度,并与另一个具有更高规模和/或更高的十进制列联合精确。结果值都具有较低的比例和精度。
这似乎不正确,因为this page表明当UNIONing时,精度将被调整为最适合它的精度。
使用此示例可以很容易地看出问题:
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
但是,我正在使用Entity Framework 6,并且无法控制SQL生成的内容。有没有办法强制Entity Framework在执行SUM时强制转换为更高的精度,或者其他一些方法来确保正确的行为?
编辑: 我不确定为什么这被标记为浮点问题的副本。这与浮点无关 - 它使用十进制 - 一种定点数据类型。
答案 0 :(得分:2)
扩展Martin Smith在评论中提到的内容,这就是正在发生的事情:
从sql server documentation on SUM开始,decimal(p, s)
类型的SUM结果始终为decimal(38, s)
。
因此,UNION前半部分的输入为decimal(38, 2)
,下半部分为decimal(38, 8)
This page表示当UNIONing时,结果精度为max(s1, s2) + max(p1-s1, p2-s2)
,且比例为max(s1, s2)
因此,将s1 = 2
,s2 = 8
,p1, p2 = 38
放入其中,我们得到的精度为44,等级为8。
然而,相同页面的状态结果精度和比例的绝对最大值为38.当结果精度大于38时,相应的比例会减小,以防止结果的整数部分被截断。< / em>的
因此,它将比例缩小了6(降低到2),使总精度降低到38。
这解释了行为,但没有提供解决方案。 也就是说,有选择:
.Conact()
而不必担心SQL行为。 Sum()
之前将.Conact() or .Union()
的结果转换为浮点数或双精度数。显然,这引入了许多其他问题,但在某些情况下它可能是可行的。在我的情况下,我可能会选择#2,因为肯定会有其他地方将这两个表格相加并且&amp;联合,我不希望其他devleopers认识到他们会受到这种SQL服务器行为的影响(从EF的角度来看,我们正在处理.Net小数)。