Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Data Management

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

Authors

Search

XML Feeds

Google Ads

« Including an Aggregated Column's Related ValuesOperand type clash: date is incompatible with int error when trying to do +1 on a date data type in SQL Server 2008 »
comments
Rate Post:
submit to reddit Digg!FacebookDotnetkicks

Occasionally, it's necessary to convert character data (char, nchar, varchar, nvarchar) to a number. Before doing so, it is best to make sure that the value can be converted to a number.

IsNumeric would be the obvious choice, but has some problems because it allows for unexpected characters during the conversion. For example, the following strings will return true from the IsNumeric function.

$12.09
1.4e3
2d4

Technically, all of these are numbers.

  1. SELECT CONVERT(MONEY, '$12.09')
  2. SELECT CONVERT(FLOAT, '1.4e3')
  3. SELECT CONVERT(FLOAT, '2d4')

Often times, we don't want to allow the dollar sign or scientific notation.

To make sure a value can be converted to an integer, you can append .0e0 to the end of the string before checking. If the original value had a decimal point, then adding another decimal point will cause the value to not be numeric. Similarly, adding e0 to a value that is already expressed in scientific notation will cause IsNumeric to return false.

Consider the following values:

Original   + '.0e0'    + 'e0'
--------   ----------  --------
$12.09     $12.09.0e0  $12.09e0
1.4e3      1.4e3.0e0   1.4e3e0
2d4        2d4.0e0     2d4e0
3.7        3.7.0e0     3.7e0
412        412.0e0     412e0

Notice how the second column will only evaluate to true for the value that can be converted to an integer. Also notice how the 3rd column will only evaluate to true for the last 2 values.

You can create your own User Defined Function to check for integers, like so:

  1. CREATE FUNCTION dbo.IsInteger(@VALUE VARCHAR(18))
  2. RETURNS BIT
  3. AS
  4. BEGIN
  5.  
  6.   RETURN IsNull(
  7.      (SELECT CASE WHEN CHARINDEX('.', @VALUE) > 0
  8.                   THEN CASE WHEN CONVERT(INT, PARSENAME(@VALUE, 1)) <> 0
  9.                             THEN 0
  10.                             ELSE 1
  11.                             END
  12.                   ELSE 1
  13.                   END
  14.       WHERE ISNUMERIC(@VALUE + 'e0') = 1), 0)
  15.  
  16. END

To use this new function:

  1. SELECT CONVERT(INT, field)
  2. FROM   TABLE
  3. WHERE  dbo.IsInteger(field) = 1

If you want to allow fractional numbers, then you can add e0 to the isnumeric test.

  1. SELECT ISNUMERIC('$12.09' + 'e0')
  2. SELECT ISNUMERIC('1.4e3' + 'e0')
  3. SELECT ISNUMERIC('2d4' + 'e0')
  4. SELECT ISNUMERIC('3.7' + 'e0')

Again, you can create a User Defined Function to test this.

  1. CREATE FUNCTION IsNumber(@VALUE VARCHAR(18))
  2. RETURNS BIT
  3. AS
  4. BEGIN
  5.   RETURN (SELECT ISNUMERIC(@VALUE + 'e0'))
  6. END

After creating the User Defined Functions, you can test it with the following code.

  1. DECLARE @Temp TABLE(DATA VARCHAR(18))
  2.  
  3. INSERT INTO @Temp VALUES('$12.09')
  4. INSERT INTO @Temp VALUES('1.4e3')
  5. INSERT INTO @Temp VALUES('2d4')
  6. INSERT INTO @Temp VALUES('3.7')
  7. INSERT INTO @Temp VALUES('412')
  8.  
  9. SELECT DATA,
  10.        ISNUMERIC(DATA) AS [ISNUMERIC],
  11.        dbo.IsInteger(DATA) AS IsInteger,
  12.        dbo.IsNumber(DATA) AS IsNumber
  13. FROM   @Temp

About the Author

George has been developing software professionally for 19 years, first for the department of defense, and then for various other companies. In 1998, George started his software company, Orbit Software, specializing in School Bus Transportation software. His specialty is refining SQL Server queries to deliver optimal performance.
Social SitingsTwitterLTD RSS Feed
2383 views
submit to reddit Digg!FacebookDotnetkicks

Comments and Feedback

8 comments

Comment from: SQLDenis [Member] Email
*****
Very cool George, I am sure this will be very useful for a lot of our readers
07/15/09 @ 08:23
Comment from: Naomi [Member] Email
*****
Can you compare your approach with this
http://berezniker.com/content/pages/sql/microsoft-sql-server/isnumericex-udf-data-type-aware
07/15/09 @ 18:27
Comment from: George Mastros [Member] Email
Naomi,

The function at the link you posted could be pretty handy. My function executes faster (almost twice as fast), but the function you linked to has more features.

It's the classic trade-off.
07/15/09 @ 21:19
Comment from: Joseph [Visitor]
Is this post a copy of http://www.tek-tips.com/faqs.cfm?fid=6423 ?
07/19/09 @ 02:41
Comment from: Bruce W Cassidy [Visitor]
****-
Since the number is already in a varchar, wouldn't it be quicker to use something like the following?

if (@value like '%[^0-9]%) return 0 else return 1;
07/19/09 @ 14:38
Comment from: gunasundari [Visitor]
*****
This is useful article..
07/20/09 @ 00:18
Comment from: SQLDenis [Member] Email
*****
Joseph,

The author of this post and that FAQ is the same person
07/20/09 @ 07:52
Comment from: Grady Christie [Visitor] · http://www.centralfreight.com
*****
Thank you. I had been using isnumeric() for a while and someone entered only a decimal point causing some problems.
This was a huge time saver for me; thanks for submitting.
Grady Christie
08/05/09 @ 12:32

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)