控制台和JDBC中的十进制截断/舍入差异

问题描述:

我在使用一些小数精度将一个double值插入到数据库表时遇到问题。我正在使用MS SQL Server版本10.0.4000 下面是一个示例表,其中十进制列有4位小数。控制台和JDBC中的十进制截断/舍入差异

create table test (
test decimal (18,4)) 

当我插入通过MSSQL控制台值“36.78675”,因为该领域是仅有的4位小数它被四舍五入36.7868。这可以。

DECLARE @T DECIMAL(18, 5) 

SET @T = 36.78675 

insert into test values(@T) 

select * from test 

但是当我通过我的Java代码执行相当于插入(用事先准备好的声明)(MS SQL JDBC驱动程序),数据被存储在表36.7867。如果我有像36.786750001这样的值,那么控制台和JDBC都会轮询到36.7868。 我使用的java对象是double。我使用double值调用setDouble()。这里它会自动选择数据类型。但是有另一种JDBC方法需要使用对象和数据类型。使用这个,我测试了DECIMAL和FLOAT类型。所有结果都一样。我甚至将jdbc驱动程序更改为I-net。也有同样的结果。

有人知道为什么四舍五入通过驱动程序工作不同吗?是否有任何设置使其表现得像控制台?

+0

说“SQL Server控制台”,你的意思是SQL Server Management Studio? – abatishchev 2013-02-20 07:16:14

+0

@abatishchev是的 – 2013-02-20 09:23:39

这是因为二进制浮点的性质,这就是你用double(用Java)的东西。

最接近36.7875的double确切

36.7867499999999978399500832892954349517822265625 

这将向下调整至36.7867。而最接近36.78750001的double确切

36.786750000099999624580959789454936981201171875 

将被四舍五入至36.7878。这就是你得到这种行为的原因。控制台大概将输入视为十进制数,而不是完全转换为二进制浮点。

如果精确的十进制数字对您很重要,那么您可能不应该使用二进制浮点类型 - 请改为使用BigDecimal

你应该真的考虑你的价值代表什么。如果它是一个物理连续值,例如身高,身高或体重,那么使用double毕竟可能是适当的 - 但不应该让这种情况挂断。如果这是一个人工构造与离散(基于十进制)值,如货币值,那么你应该肯定使用BigDecimal,或者简单地缩放一个整数。

+0

感谢您的详细信息。不仅仅是精确性,我的问题是java路由和数据库的默认截断/舍入不一致。当值为“36.78675”时,Java舍入为36.7868,但如果在存储之前没有特别舍入值,则数据库中的存储值为“36.7867”。我需要对数据进行回溯,并与java代码中的值进行比较。在这里我不会得到一个匹配,因为我比较36.7868(java代码)和36.7867(databse)。 – 2013-02-20 07:32:45

+2

@BijuSanakan:我的观点是'double'变量*的值不能*为36.78675。这是不可能的。这就像试图用十进制表示法写下“三分之一”的确切值。同样,如果“36.78675”的确切值对您很重要,您应该使用“BigDecimal”。 – 2013-02-20 07:34:37

+0

我同意你的意见。 但我的问题是为什么它在java和mssql中的相同数字36.78675的四舍五入。 公共静态无效roundUnits(双V1) { 返回java.util.Math.round(V1 * 10000)/ 10000; } double d = 36.78675; System.out.println(roundUnits(d)); 当我打电话给上面的代码时,它打印出36.7868。 我期待从MSSQL有相同的行为。但在MSSQL中,它被存储为36.7867 – 2013-02-20 09:05:14