2009-04-14 116 views
2

如果我有一個參數化的存儲過程,它接受一個varchar(10)值並將其轉換爲int,那麼我當前必須確保該值不大於最大int值的varchar等效值。防止SQL列溢出

IF @Criteria <= '2147483647' 
    SET @Id = CONVERT(int, @Criteria) 

我的問題:是否有更好的方法來防止從varchar值轉換時溢出int列?

編輯:是的顯然,如果我覺得價值會合理地包含接近最大值的東西,我可以擴展到BigInt。這實際上意味着處理對這個存儲過程的不正確調用,並且在結果值可能溢出所需數據類型的情況下,這只是一個關於使用Convert()的通用問題。

回答

3

要處理各種條件(空格,小數等),請將轉換器包裝在TRY/CATCH中(如果無法在客戶端上清理)。假設SQL Server 2005

... 
BEGIN TRY 
    SET @Id = CONVERT(int, @Criteria) 
END TRY 
BEGIN CATCH 
    SET @Id = NULL 
END CATCH 
... 
1

最簡單和最好的方法是在源處處理它,這是創建varchar的任何地方。或者解釋一下你的意思是「防止溢出」。當varchar實際上太長時,你期望發生什麼?

+0

預期的結果是存儲過程不會返回任何行,而不是在我的數據庫讀取器中導致異常,但是我只是按照gbn的建議在客戶端上做更多的驗證。 – TheMissingLINQ 2009-04-14 16:16:12

1

如果你通過空格怎麼辦? - 它將通過IF條件但轉換失敗。你也應該使用ISNUMERIC()。

IF @Criteria <= '2147483647' AND ISNUMERIC(@Criteria) 
     SET @Id = CONVERT(int, @Criteria) 
+0

非常好的一點,謝謝。 – TheMissingLINQ 2009-04-14 16:01:06

+0

在十進制或浮點值上失敗...... – gbn 2009-04-14 16:05:50

1

一個更好的問題可能是你爲什麼要存儲作爲varchars的整數,它們會溢出它們的目標列。我不太確定你可以做什麼來完全防止溢出;你可以考慮把Id切換到一個無符號整數,所以你可以得到2^32位可用(我猜測Criteria從不是負數,因爲你將它分配給Id列)。我不確定SQL Server是否支持它,但MySQL有BIGINT列,最高可達2^64(2^63,如果你想簽名)。

+0

SQL Server確實支持signed bigint(-2^63到2^63-1)。 – 2009-04-14 16:48:10

3

您的測試將無法可靠地工作。

如果@Criteria包含'11111111111111111111',它排序的次數少於您的幻數,因爲您正在進行字符串比較。

1

首先,您的輸入長度爲10看起來像你不期望(或接受)負值。 int的下界是-2147483648,它將用11個字符的字符串表示。

從上面的DJ代碼構建而來,我建議你在CONVERT /比較之前放置ISNUMERIC()調用。

IF ISNUMERIC(@Criteria) = 1 
    AND CONVERT(bigint, @Criteria) <= 2147483647 
     SET @Id = CONVERT(int, @Criteria) 

這首先轉換爲bigint,然後進行比較。這裏有幾個測試案例:

DECLARE @Id   int 
DECLARE @Criteria varchar(10) 

PRINT 'Expect failure (NULL)' 
SET @Criteria = '2147483648' 
SET @Id = NULL 

IF ISNUMERIC(@Criteria) = 1 
    AND CONVERT(bigint, @Criteria) <= 2147483647 
     SET @Id = CONVERT(int, @Criteria) 

SELECT @Id AS '@Id', @Criteria AS '@Criteria', CONVERT(bigint, @Criteria) AS 'Converted to bigint' 

PRINT 'Expect success' 
SET @Criteria = '2147483647' 
SET @Id = NULL 

IF ISNUMERIC(@Criteria) = 1 
    AND CONVERT(bigint, @Criteria) <= 2147483647 
     SET @Id = CONVERT(int, @Criteria) 

SELECT @Id AS '@Id', @Criteria AS '@Criteria', CONVERT(bigint, @Criteria) AS 'Converted to bigint' 

PRINT 'Expect failure but get success because @Criteria is truncated to 10 characters' 
SET @Criteria = '11111111111111111111' 
SET @Id = NULL 

IF ISNUMERIC(@Criteria) = 1 
    AND CONVERT(bigint, @Criteria) <= 2147483647 
     SET @Id = CONVERT(int, @Criteria) 

SELECT @Id AS '@Id', @Criteria AS '@Criteria', CONVERT(bigint, @Criteria) AS 'Converted to bigint' 

和結果:

Expect failure (NULL) 
     @Id @Criteria Converted to bigint 
----------- ---------- -------------------- 
     NULL 2147483648   2147483648 

Expect success 
     @Id @Criteria Converted to bigint 
----------- ---------- -------------------- 
2147483647 2147483647   2147483647 

Expect failure but get success because @Criteria is truncated to 10 characters 
     @Id @Criteria Converted to bigint 
----------- ---------- -------------------- 
1111111111 1111111111   1111111111 

注意,通過「11111111111111111111」的實際工作,因爲輸入被截斷。