Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL Server总和和并集丢失十进制精度_Sql Server_Entity Framework - Fatal编程技术网

Sql server 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))

这是一个与实体框架和SQL Server(2016)相关的问题

我注意到SQL server中有一些奇怪的行为,当以较低的比例和精度对十进制列求和,并将其与另一个具有较高比例和精度的十进制列合并时。结果值都具有较低的比例和精度

这似乎不正确,因为这表明在联合时,精度将被调整到适应它所需的最宽范围

这个例子很容易看出问题:

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

这可以解释这种行为,但不能提供解决方案。 也就是说,有以下几种选择:

  • 将联合体的两部分作为单独的查询发出。此时,我们将处理.Net十进制,我们可以
    .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?我想它必须这样做,以允许潜在的数百万行被加在一起?