SQL - безопасно понижать BIGINT до INT - PullRequest
9 голосов
/ 17 августа 2011

У меня есть CSV, который я импортирую в нашу базу данных.Один из «столбцов» содержит данные, которые должны быть INT, но некоторые строки имеют числа, которые попадают только в диапазон BIGINT (потому что это тестовые данные от одного из наших партнеров).Мы храним INT внутренне и не хотим менять.

Я хочу безопасно снизить рейтинг BIGINT до INT.Под «безопасным» я подразумеваю, что в случае арифметического переполнения не должно возникать ошибок.Если приведение / преобразование выполнено успешно, я хочу, чтобы мой сценарий продолжался.Если это не удается, я хочу, чтобы оно замкнуло.Я не могу понять правильный синтаксис.Вот что у меня есть:

DECLARE @UserIDBigInt BIGINT = 9723021913; -- actually provided by query param
--Setting within the INT range successfully converts
--SET @UserIDBigInt = 5;
DECLARE @UserID INT = CONVERT(INT, @UserIDBigInt);
--DECLARE @UserID INT = CAST(@UserIDBigInt AS INT);
SELECT @UserIDBigInt
SELECT @UserID
IF @UserID IS NOT NULL BEGIN
    SELECT 'Handle it as reliable data'
END

Я думал о сравнении @UserIDBigInt с допустимым диапазоном INT (от -2 ^ 31 (-2,147,483,648) до 2 ^ 31-1 (2,147,483,647)), но мне действительно не нравится такой подход.Это мой запасной вариант.Я надеялся на некоторые языковые конструкции или встроенные функции, которые я мог бы использовать.Если мне абсолютно необходимо сравнить с допустимым диапазоном, есть ли хотя бы какие-нибудь встроенные константы (например, int #MinValue & int.MaxValue в C #)?

EDIT : исправлена ​​опечатка.

Ответы [ 4 ]

6 голосов
/ 18 августа 2011

Добавьте их в ваш скрипт:

SET ARITHABORT OFF;
SET ARITHIGNORE ON;

Это преобразует любые значения переполнения в NULL.

Более подробная информация здесь: http://msdn.microsoft.com/en-us/library/ms184341.aspx

4 голосов
/ 18 августа 2011

Приведите bigint к varbinary, затем сохраните нижнюю половину до @UserID и проверьте верхнюю половину:

  • если верхняя половина - все 0, а нижняя половина представляет неотрицательное значение, @UserID тогда содержит правильное значение int;

  • если верхняя половина - все 1, а @UserID отрицательно, то тоже все в порядке;

  • в противном случае возникает арифметическое переполнение.

Вот реализация:

DECLARE @UserIDBigInt BIGINT = 9723021913;
DECLARE @UserID INT, @HighInt INT;

WITH v AS (SELECT CAST(@UserIDBigInt AS varbinary) AS bin)
SELECT
  @HighInt = SUBSTRING(bin, 1, 4),
  @UserID  = SUBSTRING(bin, 5, 4)
FROM v;

IF (@HighInt = 0 AND @UserID >= 0 OR @HighInt = -1 AND @UserID < 0) BEGIN
    SELECT 'Handle it as reliable data'
END
1 голос
/ 18 августа 2011

Я не уверен, что это лучший ответ, но это тот, который я придумал ранее самостоятельно. Можно перехватить исключение / ошибку и изящно продолжить выполнение.

Пример:

DECLARE @UserIDBigInt BIGINT = 9723021913;
DECLARE @UserID INT;
BEGIN TRY
    SET @UserID = @UserIDBigInt;
END TRY BEGIN CATCH
END CATCH

IF @UserID IS NULL BEGIN
    SELECT 'Handle it as unreliable data'
    RETURN
END

SELECT 'Handle it as reliable data'
0 голосов
/ 18 августа 2011

Вы также можете преобразовать значение в строку, обрезать его до длины и преобразовать в int.не лучший способ, но безопасный легкий путь наверняка

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