5

調試一些與財務相關的SQL代碼,發現數值(24,8)數學精度存在一個奇怪的問題。SQL server 2005數字精確損失

運行在您的MSSQL以下查詢,你會得到A + B * C表達式的結果是0.123457

選擇, B, C, A + B * C FROM ( SELECT CAST (0.12345678 AS NUMERIC(24,8))AS A, CAST(0 AS NUMERIC(24,8))AS B, CAST(500 AS NUMERIC(24,8))爲C )筆

所以我們失去了2個重要的符號。試圖以不同的方式得到這個修復,我得到了中間乘法結果(這是零!)到數值(24,8)的轉換可以正常工作。

最後有一個解決方案。但是我仍然有一個問題 - 爲什麼MSSQL會以這種方式運行,以及我的示例中實際發生了哪些類型轉換?

回答

7

正如浮點類型的添加不準確,如果超過精度,則小數類型的乘法可能不準確(或導致不準確)。見Data Type Conversiondecimal and numeric

由於您乘以NUMERIC(24,8)NUMERIC(24,8),並且SQL Server只會檢查類型而不是內容,所以當它不能保存全部48位數字時,它可能會嘗試保存潛在的16位非十進制數字(24 - 8)的精度(最高38)。結合其中兩個,你會得到32個非十進制數字,只留下6個十進制數字(38-32)。

因此原來的查詢

SELECT A, B, C, A + B * C 
FROM (SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A, 
    CAST(0 AS NUMERIC(24,8)) AS B, 
    CAST(500 AS NUMERIC(24,8)) AS C) T 

降低到

SELECT A, B, C, A + D 
FROM (SELECT CAST(0.12345678 AS NUMERIC(24,8)) AS A, 
    CAST(0 AS NUMERIC(24,8)) AS B, 
    CAST(500 AS NUMERIC(24,8)) AS C, 
    CAST(0 AS NUMERIC(38,6)) AS D) T 

再次,NUMERIC(24,8)NUMERIC(38,6)之間,SQL Server將盡量節省的潛力32位非小數,所以A + D減少了

SELECT CAST(0.12345678 AS NUMERIC(38,6)) 

哪個gi經過四捨五入之後,你會發現0.123457

+0

您的意思是NUMERIC(32,6))?如果總和必須是38 – Edmondo1984 2012-12-03 19:47:08

+0

@ Edmondo1984請閱讀鏈接並理解這兩個數字的含義。 – 2012-12-03 20:06:57

0

繼邏輯所指出的eed3si9n和你在你的問題說,這似乎是在做數學運算時,最好的辦法是將它們提取到一個功能,另外每個操作後指定精度,

這本如果功能可能如下所示:

create function dbo.myMath(@a as numeric(24,8), @b as numeric(24,8), @c as numeric(24,8)) 
returns numeric(24,8) 
as 
begin 
    declare @d as numeric(24,8) 
    set @d = @b* @c 
    return @a + @d 
end