Created
June 27, 2012 16:15
-
-
Save josheinstein/3005142 to your computer and use it in GitHub Desktop.
T-SQL Parse Int without fear of exception
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- ============================================= | |
-- Author: Josh Einstein | |
-- Create date: 2012-06-27 | |
-- Description: Converts a string to Int64 and returns null if the conversion fails. | |
-- I have tried pretty hard to ensure this can never cause an error. Let me know if | |
-- I have missed something! | |
-- ============================================= | |
CREATE FUNCTION [Utils].[TryParseInt64] (@Value nvarchar(255)) RETURNS bigint AS | |
BEGIN | |
IF @Value IS NULL RETURN NULL; | |
SET @Value = LTRIM(RTRIM(@Value)) | |
-- Basic checks for way too long strings or empty strings | |
IF LEN(@Value) = 0 OR LEN(@Value) > 38 RETURN NULL; | |
-- Since ISNUMERIC returns true for exponent and decimal | |
-- number formats, we will tack on a string that won't change | |
-- the actual value but will make such strings malformed. | |
-- example, if '1.5e15' is the string we'll check '1.5e15.0e0' | |
-- which ISNUMERIC won't report as numeric. | |
IF ISNUMERIC(@Value + '.0e0') = 0 RETURN NULL; | |
-- Use numeric(38,0) because | |
-- a) it's the most number of digits we can parse using built-in types | |
-- b) we already verified the string contains no decimals | |
-- Once we have a numeric type, we can do range checks for int type | |
DECLARE @Result numeric(38,0) = CONVERT(numeric(38,0), @Value); | |
IF @Result > 9223372036854775807 OR @Result < -9223372036854775808 RETURN NULL; | |
RETURN CONVERT(bigint, @Result); | |
END |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- these should not parse because of the string format | |
IF Utils.TryParseInt64(NULL) IS NOT NULL RAISERROR('Fail', 16, 1); | |
IF Utils.TryParseInt64('') IS NOT NULL RAISERROR('Fail', 16, 1); | |
IF Utils.TryParseInt64(' ') IS NOT NULL RAISERROR('Fail', 16, 1); | |
IF Utils.TryParseInt64(' ') IS NOT NULL RAISERROR('Fail', 16, 1); | |
IF Utils.TryParseInt64('.') IS NOT NULL RAISERROR('Fail', 16, 1); | |
IF Utils.TryParseInt64('0.0') IS NOT NULL RAISERROR('Fail', 16, 1); | |
IF Utils.TryParseInt64('0.') IS NOT NULL RAISERROR('Fail', 16, 1); | |
IF Utils.TryParseInt64('.0') IS NOT NULL RAISERROR('Fail', 16, 1); | |
IF Utils.TryParseInt64('1,000') IS NOT NULL RAISERROR('Fail', 16, 1); | |
IF Utils.TryParseInt64('$1000') IS NOT NULL RAISERROR('Fail', 16, 1); | |
IF Utils.TryParseInt64('1.0e0') IS NOT NULL RAISERROR('Fail', 16, 1); | |
IF Utils.TryParseInt64('0 1') IS NOT NULL RAISERROR('Fail', 16, 1); | |
-- these should not parse because they overflow | |
IF Utils.TryParseInt64('9999999999999999999') IS NOT NULL RAISERROR('Fail', 16, 1); -- # of digits ok, but too large | |
IF Utils.TryParseInt64('-9999999999999999999') IS NOT NULL RAISERROR('Fail', 16, 1); -- # of digits ok, but too small | |
IF Utils.TryParseInt64('9223372036854775808') IS NOT NULL RAISERROR('Fail', 16, 1); -- # of digits ok, max + 1 | |
IF Utils.TryParseInt64('-9223372036854775809') IS NOT NULL RAISERROR('Fail', 16, 1); -- # of digits ok, min - 1 | |
IF Utils.TryParseInt64('99999999999999999999') IS NOT NULL RAISERROR('Fail', 16, 1); -- one too many digits | |
IF Utils.TryParseInt64('-99999999999999999999') IS NOT NULL RAISERROR('Fail', 16, 1); -- one too many digits | |
IF Utils.TryParseInt64('99999999999999999999999999999999999999') IS NOT NULL RAISERROR('Fail', 16, 1); -- max digits for numeric(38) | |
IF Utils.TryParseInt64('-99999999999999999999999999999999999999') IS NOT NULL RAISERROR('Fail', 16, 1); -- max digits for numeric(38) | |
IF Utils.TryParseInt64('99999999999999999999999999999999999999999999999999') IS NOT NULL RAISERROR('Fail', 16, 1); -- way too many digits (50) | |
IF Utils.TryParseInt64('-99999999999999999999999999999999999999999999999999') IS NOT NULL RAISERROR('Fail', 16, 1); -- way too many digits (50) | |
-- these should parse fine! | |
IF NOT (Utils.TryParseInt64('0') = 0) RAISERROR('Fail', 16, 1); | |
IF NOT (Utils.TryParseInt64('-0') = 0) RAISERROR('Fail', 16, 1); | |
IF NOT (Utils.TryParseInt64('1') = 1) RAISERROR('Fail', 16, 1); | |
IF NOT (Utils.TryParseInt64(' 1') = 1) RAISERROR('Fail', 16, 1); | |
IF NOT (Utils.TryParseInt64('1 ') = 1) RAISERROR('Fail', 16, 1); | |
IF NOT (Utils.TryParseInt64(' 1 ') = 1) RAISERROR('Fail', 16, 1); | |
IF NOT (Utils.TryParseInt64('0001') = 1) RAISERROR('Fail', 16, 1); | |
IF NOT (Utils.TryParseInt64('-1') = -1) RAISERROR('Fail', 16, 1); | |
IF NOT (Utils.TryParseInt64(' -1') = -1) RAISERROR('Fail', 16, 1); | |
IF NOT (Utils.TryParseInt64('-1 ') = -1) RAISERROR('Fail', 16, 1); | |
IF NOT (Utils.TryParseInt64(' -1 ') = -1) RAISERROR('Fail', 16, 1); | |
IF NOT (Utils.TryParseInt64('-0001') = -1) RAISERROR('Fail', 16, 1); | |
IF NOT (Utils.TryParseInt64('9223372036854775807') = 9223372036854775807) RAISERROR('Fail', 16, 1); -- max | |
IF NOT (Utils.TryParseInt64('-9223372036854775808') = -9223372036854775808) RAISERROR('Fail', 16, 1); -- min |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment