2013-02-20 85 views
1

我在使用一些小數精度將一個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

回答

4

這是因爲二進制浮點的性質,這就是你用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