Предотвращение переполнения столбцов Sql - PullRequest
2 голосов
/ 14 апреля 2009

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

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

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

Редактировать: Да, очевидно, если бы я почувствовал, что значение будет на законных основаниях содержать что-то близкое к максимальному значению, которое я мог бы расширить до BigInt. Это действительно предназначено для обработки неправильных вызовов этого хранимого процесса, и это был просто вопрос общего назначения об использовании Convert () в случаях, когда результирующее значение может переполнять требуемый тип данных.

Ответы [ 6 ]

3 голосов
/ 14 апреля 2009

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

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

3 голосов
/ 14 апреля 2009

Чтобы справиться с различными условиями (пробелы, десятичные дроби и т. Д.), Заверните конвертирование в TRY / CATCH, если вы не можете выполнить очистку на клиенте. Предполагается, что SQL Server 2005

...
BEGIN TRY
   SET @Id = CONVERT(int, @Criteria)
END TRY
BEGIN CATCH
   SET @Id = NULL
END CATCH
...
1 голос
/ 14 апреля 2009

Во-первых, ваша длина ввода 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' на самом деле работает, так как ввод усекается.

1 голос
/ 14 апреля 2009

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

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

1 голос
/ 14 апреля 2009

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

IF @Criteria <= '2147483647' AND ISNUMERIC(@Criteria)
        SET @Id = CONVERT(int, @Criteria)
1 голос
/ 14 апреля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...