开发者

SQL - safely downcast BIGINT to INT

开发者 https://www.devze.com 2023-03-28 23:47 出处:网络
I have a CSV I\'m importing into our database. One o开发者_开发技巧f the \"columns\" contains data that should be an INT but some rows have numbers that only fall in the BIGINT range (because they\'re

I have a CSV I'm importing into our database. One o开发者_开发技巧f the "columns" contains data that should be an INT but some rows have numbers that only fall in the BIGINT range (because they're test data from one of our partners). We store INT internally and have no desire to change.

I want to safely downcast from BIGINT to INT. By safely, I mean no errors should be raised if an arithmetic overflow happens. If the cast/conversion succeeds, I want my script to go on. If it fails, I want it to short-circuit. I can't seem to figure out the proper syntax. This is what I've got:

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

I've thought about comparing @UserIDBigInt to the valid range of an INT (-2^31 (-2,147,483,648) to 2^31-1 (2,147,483,647)), but I really don't like that approach. That's my fallback. I was hoping for some language constructs or built-in functions I could use. If I absolutely have to compare to the valid range, are there at least some built-in constants (like C#'s int.MinValue & int.MaxValue)?

EDIT: Corrected typo.


Add these to your script:

SET ARITHABORT OFF;
SET ARITHIGNORE ON;

This will convert any overflow values to NULL.

More info here: http://msdn.microsoft.com/en-us/library/ms184341.aspx


Cast your bigint to varbinary, then store the lower half to @UserID and check the upper half:

  • if the upper half is all 0's and the lower half represents a non-negative value, @UserID then contains the correct int value;

  • if the upper half is all 1's and @UserID is negative, it's all right too;

  • otherwise there's an arithmetic overflow.

Here's an implementation:

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


I'm not sure this is the best answer but it is one I came up with earlier on my own. It is possible to catch the exception/error and gracefully continue execution.

Example:

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'


You could also convert the value to a string, trim it to length and convert to int. not the best way, but a safe easy way for sure

0

精彩评论

暂无评论...
验证码 换一张
取 消