2009-04-14 3 views
2

Если у меня есть параметризованная хранимая процедура, которая принимает значение varchar (10) и преобразует его в int, в настоящее время я должен убедиться, что значение не превышает эквивалент varchar максимального значения int.Предотвращение переполнения столбцов Sql

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

Мой вопрос: есть ли лучший способ предотвратить переполнение столбца int при преобразовании из значения varchar?

Редактировать: Да, очевидно, если бы я чувствовал, что значение должно было законно содержать что-то близкое к максимальному значению, которое я мог бы расширить до 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

Самый простой и лучший способ - разобраться с ним в источнике, который находится там, где создается варчар. Или объясните, что вы подразумеваете под «предотвращением переполнения». Что вы ожидаете, когда вахчар на самом деле слишком длинный?

+0

Ожидаемый результат будет заключаться в том, что хранимая процедура не возвращает никаких строк, а не вызывает исключение в моем БД-ридере, но я просто собираюсь сделать еще немного проверки на клиенте, как предположил gbn. – TheMissingLINQ

1

Что делать, если вы проходите пробелы? - он пройдет условие IF, но не сработает при преобразовании. Вы также должны использовать ISNUMERIC().

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

Очень хороший момент, спасибо. – TheMissingLINQ

+0

Это не соответствует десятичным или плавающим значениям ... – gbn

1

Лучше вопрос может быть, почему вы храните, как и VARCHARS, целые числа, которые выходят из столбца назначения. Я не слишком уверен, что вы можете сделать, чтобы предотвратить переполнения полностью; вы можете рассмотреть возможность переключения Id на целое число без знака, поэтому вы можете получить до 2^32 бита (я предполагаю, что критерий никогда не является отрицательным, поскольку вы назначаете его столбцу Id).

Я не уверен, поддерживает ли SQL Server его, но MySQL имеет столбцы BIGINT, которые идут до 2^64 (2^63, если вы хотите, чтобы они были подписаны).

+0

SQL Server поддерживает подписанный bigint (-2^63 до 2^63-1). –

3

Ваш тест не будет надежно работать.

Если @Criteria содержит «11111111111111111111», он сортирует меньше, чем ваше магическое число, потому что вы выполняете сравнение строк.

1

Во-первых, ваша длина ввода 10 выглядит так, будто вы не ожидаете (или не принимаете) отрицательных значений. Нижняя граница для int равна -2147483648, которая будет представлена ​​11-символьной строкой.

Основываясь на коде диджея сверху, я предлагаю вам поместить вызов 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» на самом деле работает, так как вход усекается.

+0

Это не работает с поплавком, десятичным, встроенным пространством и, возможно, с множеством других случаев. –

Смежные вопросы