Skip to content

Instantly share code, notes, and snippets.

@josheinstein
Created June 27, 2012 16:15
Show Gist options
  • Save josheinstein/3005142 to your computer and use it in GitHub Desktop.
Save josheinstein/3005142 to your computer and use it in GitHub Desktop.
T-SQL Parse Int without fear of exception
-- =============================================
-- 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
-- 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