mo.notono.us

Thursday, October 20, 2005

SQL: IsReallyInteger

There are a number of problems with the ISNUMERIC function in TSQL, some of which were causing us grief recently. So I went looking for a solution, and found a UDF at aspfaq. What I really needed though, was a check for integers, so I concocted one as follows:

----------------------------------------------------------------------------
--Purpose: Checks that the input string is really an integer of the specified type.  
-- To be used in place of the ISNUMERIC function, as it can't be trusted.
-- See http://www.sql-server-performance.com/forum/topic.asp?TOPIC_ID=10194
--Inspired by: http://www.aspfaq.com/show.asp?id=2390 
--Created: 10/20/05 by Oskar Austegard.
--Updated: 11/16/05 by Oskar Austegard - fixed a rather serious bug...
----------------------------------------------------------------------------
ALTER FUNCTION dbo.IsReallyInteger
(  
  @Num varchar(64), --Input string to be checked
  @Type varchar(8) --Type of integer: bigint, int, smallint, tinyint
)  
RETURNS BIT  
BEGIN  
  --Get the absolute value of the number by removing a leading - or +
  DECLARE @AbsNum varchar(64)
  SET @AbsNum = CASE WHEN LEFT(@Num, 1) IN ('-', '+') THEN SUBSTRING(@Num, 2, LEN(@Num)) ELSE @Num END

  --Remove leading zeros
  WHILE LEN(@AbsNum) > 1 AND LEFT(@AbsNum, 1) = '0'
    SET @AbsNum = SUBSTRING(@AbsNum, 2, LEN(@AbsNum))

  SET @Length = LEN(@AbsNum) 
  --Reinsert the - in negative numbers
  SET @Num = CASE WHEN LEFT(@Num, 1) = '-' THEN '-' + @AbsNum ELSE @AbsNum END

  --Check for empty string or non-digits
  IF @AbsNum = '' OR PATINDEX('%[^0-9]%', @AbsNum) > 0
    RETURN 0

  --Check limits by type
  IF (@Type = 'bigint' AND (@Length < 19 OR (@Length = 19 AND (@AbsNum < '9223372036854775807' OR @Num = '-9223372036854775808'))))
    OR (@Type = 'int' AND (@Length < 10 OR (@Length = 10 AND (@AbsNum < '2147483648' OR @Num = '-2147483648'))))
    OR (@Type = 'smallint' AND (@Length < 5 OR (@Length = 5 AND (@AbsNum < '32768' OR @Num = '-32768'))))
    OR (@Type = 'tinyint' AND LEFT(@Num, 1) <> '-' AND (@Length < 3 OR (@Length = 3 AND @AbsNum < '256')))
    RETURN 1 --Success
  --Else
  RETURN 0 --Failure
END  

I then wrap this function in another for the most common usage:

ALTER FUNCTION dbo.IsReallyInt
(  
 @Num varchar(64) --Input to be checked
)  
RETURNS BIT  
BEGIN  
 RETURN dbo.IsReallyInteger(@Num, 'int')
END  
Tags:

Labels:

0 Comments:

Post a Comment

<< Home