2016-03-09 98 views
2

我的任務是調試我們的一些舊代碼,並且遇到了一個問題。代碼是用VB6編寫的,我們有一個叫做RoundIt()的函數,它接受一個值,然後將其舍入到2個小數位。令人驚訝的是,函數(並且我沒有太多的VB6經驗,所以我假設它可能只是語言的一個限制)構建一個SQL字符串來執行以便將值舍入。SQL ROUND - 算術溢出的真正原因是什麼?

所以在代碼中我們有一個雙重類型的變量,我將其稱爲myVal。在這個特定的情況下,我們得到的是否是錯誤的,因爲myVal值爲0.997721736173984,建成串變得

SELECT ROUND(0.997721736173984, 2) as RoundedNum 

,這導致在該消息中「算術溢出錯誤將表達式轉換爲數據類型數值」。根據我的理解,這是由於試圖將值四捨五入爲1但無法這樣做,因爲現在返回的數據類型與ROUND函數中輸入的數據類型不同,並且這些數據類型必須相同。

我的問題是,由於這是一個動態構建的SQL字符串,它不像我們正在聲明一個帶有數據類型的SQL變量並在ROUND函數中使用它,我們只是構建字符串 - 所以究竟是什麼默認數據類型爲0.997721736173984?那麼什麼是試圖返回的數據類型是什麼?我猜測一個小數(不確定的精度或比例),並且當它試圖返回四捨五入的值時,精度或比例現在是不同的,但我只想確定。

我不是要求避免算術溢出,或確定不同的服務器上的差異,所以這個問題不是重複的建議。我的問題是什麼數據類型是從動態構建的SQL字符串輸入/輸出的,爲什麼會導致算術溢出錯誤(如果根據下面的註釋,它們具有相同的數據類型)。

+0

你確定它是'MS SQL Server'嗎? 'ROUND'需要2個參數。 – lad2025

+0

我的錯誤,我忘了添加該部分,更新問題。 – Goose

+0

什麼版本的SQL服務器?當我將代碼投入到SQL 2012中時,它不會運行。也就是說,我的想法是,SQL Server期望類似於數字(x,y),並且總數位數大於x。 – CodeMonkey1313

回答

4

如果執行此代碼:

select 0.097721736173984 RoundedNum 
into #temp 

exec tempdb.dbo.sp_help '#temp' 

你會發現它是解釋您的文字數量爲數字(15,15)。

Column_name Type Computed Length Prec Scale Nullable TrimTrailingBlanks FixedLenNullInSource Collation 
----------- ------- --------- ------ ----- ----- --------- ------------------- --------------------- --------- 
RoundedNum numeric no  9  15 15 no  (n/a)    (n/a)     NULL 

這意味着您只能使用15位數字,所有15位都必須在小數點右邊。當你舍入這個數字時,它不再適合數據類型,因此返回一個錯誤。

您可以通過顯式轉換文字來修復它。如:

select round(convert(float,0.997721736173984),2) RoundedNum 

只要捕獲所有預期的有效數字,您就可以選擇任何您想要的數據類型。 Float爲您提供範圍內最大的靈活性,但可以權衡潛在的精度損失。如果您知道您將四捨五入的所有數字爲< 1且不超過15位數,則numeric(16,15)將保留您的原始數字和舍入數字。使用數字類型時,您只需考慮數字的範圍,並確保您已分配足夠的空間來保存所有可能的結果。

這裏是一個如何SQL Server中的表達式解析數字數據類型一些更多有用信息:

Precision, Scale, and Length (Transact-SQL)

+0

感謝Brian,我正在尋找可以執行的內容來確定數據類型,這絕對有幫助。它是有道理的,四捨五入的數字將不會有相同的數據類型......你偶然知道什麼數據類型的舍入數字將是什麼? – Goose

+0

我爲你解答了一些更多的信息。 –

0

可以使用SQL_VARIANT_PROPERTY功能找到的數據類型。

SELECT 
    SQL_VARIANT_PROPERTY(x.y, 'BaseType') AS DataType, 
    SQL_VARIANT_PROPERTY(x.y, 'Precision') AS Precision, 
    SQL_VARIANT_PROPERTY(x.y, 'Scale')  AS Scale 
FROM 
    (
     VALUES 
      (0.997721736173984) 
    ) AS x(y) 
; 

在這種情況下,你有一個數字(15,15)。因爲所有可用空間都已分配給您的比例,所以您無法將比例分配爲1.

使用CAST明確設置數據類型可以解決您的問題。

SELECT 
     ROUND(CAST(0.997721736173984 AS NUMERIC(16, 15)), 2)