在SQL Server中,我创建了一个SQL数据类型为float的聚合列(我添加,多个,求和等其他列的组合)。
但是,当我多次运行相同的查询时,浮点数的最后两位数字不稳定并且会不断变化。
在浮点数下方,我得到的最后两位数字是随机的-我尝试将其转换为十进制,然后将最后两位数字切掉。
select round(convert(decimal(20,19), 0.0020042890676442646), 17,1)
select round(convert(decimal(20,19), 0.0020042890676442654), 17,1)
在SSMS中,两者的结果均为:0.0020042890676442 600 。
请记住,这里的输入常量是我从python那里获取的,因此它们可能已经被修改了。我不能直接从sql中获取它们,因为很难获得计算异常,而且我也不知道如何重现它。
但是通过pypyodbc运行到python,有时结果是python十进制。第二个语句的值类型为0.0020042890676442 700 的十进制类型,因此它看起来确实是舍入而不是截断。 >
我还注意到sql中的计算结果并不总是相同,并且浮点数的最后一位存在不稳定性-不确定如何在语法上进行测试。
强制转换为浮点数的常量为:
select convert(float,0.0020042890676442646)
select convert(float,0.0020042890676442654)
结果:0.0020042890676442 7 。
用小数点表示并四舍五入:
select round(convert(decimal(20,19), convert(float,0.0020042890676442646)), 17,1)
select round(convert(decimal(20,19), convert(float,0.0020042890676442654)), 17,1)
在两种情况下,SSMS中的结果均为:0.0020042890676442 700 。
我尝试直接将浮点数发回而不是强制转换为十进制数,但是似乎两个不稳定的数字总是在到达python时添加在末尾。即使截断也无济于事,然后添加其他随机数。
几乎好像python在传输过程中以随机方式修改了float和Decimal,或者不稳定已经存在于sql中,或者两者都存在。
我尝试在python端截断np.float64,如下所示:Truncating decimal digits numpy array of floats
但是由于sql中的最后一个浮点数可以在e15和e19之间,因此除非我将所有内容都限制在e15,否则我无法设置一致的截断级别。
答案 0 :(得分:3)
未定义聚合的处理顺序,就像未定义任何查询结果的顺序一样,除非您使用ORDER BY
子句。对于float
,顺序很重要。可以使用OVER
子句强制执行聚合处理的顺序。这是一些代码来演示:
-- demonstrate that order matters when adding floats
declare @a float
declare @b float
declare @c float
declare @d float
declare @e float
set @a = 1
set @b = 1
set @c = 9024055778268167
-- add A to B, and then add C
-- result is 9024055778268170
set @d = @a + @b
set @e = @d + @c
select cast( @e as decimal(38,0) )
-- add C to B, and then add A
-- result is 9024055778268168
set @d = @c + @b
set @e = @d + @a
select cast( @e as decimal(38,0) )
-- put these values into a table
create table OrderMatters ( x float )
insert into OrderMatters ( x ) values ( @a )
insert into OrderMatters ( x ) values ( @b )
insert into OrderMatters ( x ) values ( @c )
declare @x float
-- add them in ascending order
-- result is 9024055778268170
select @x = sum(x) over (order by x asc ) from OrderMatters
select cast(@x as decimal(38,0))
-- add them in descending order
-- result is 9024055778268168
select @x = sum(x) over (order by x desc ) from OrderMatters
select cast(@x as decimal(38,0))