Check if a string contains only number - sql

I am trying to check if a string contains only valid number in the following format
123.456
123
.356
But it should reject anything that contains non-numbers including double dots. Here are some invalid formats
d123.456
123d
12d3
d.1256
12d.456
12.d12
12.d45d
12.45.56
I have done the following
SELECT CASE WHEN '123.00' NOT LIKE '%[^0-9.]%' THEN 'Valid' ELSE 'Invalid' END
When seems to work except for the case where there is more than one dot in the string.
How can I tweak the regular expression to only allow one dot otherwise return 'Invalid'?

I would suggest try_convert():
select (case when try_convert(col, float) is not null then 'valid' else 'invalid' end)
The one possible downside is exponential format; 1e6 is a valid number for instance.
An alternative is the where approach; you just need more complete logic:
select (case when col like '%[^0-9.]%' then 'invalid'
when col like '%.%.%' then 'invalid'
else 'valid'
end)

There's a sql server built in function:
Select CASE WHEN isnumeric([fieldname]) THEN 'Valid' ELSE 'Invalid" END

If you're not tied to regular expressions, SQL Server has an ISNUMERIC function you can use for this.
ISNUMERIC returns 1 when the input expression evaluates to a valid numeric data type; otherwise it returns 0.

TRY_PARSE will let you compare the input value to any/all numeric datatypes you decide to allow -- for example:
SELECT
TRY_PARSE('123.456' as int) as [int],
TRY_PARSE('123.0' as float) as [float],
TRY_PARSE('d123.456' as int) as [int],
TRY_PARSE('d123.456' as float) as [float]
FWIW -- ISNUMERIC is often suggested, and is certainly the best-sounding function name :-) -- but doesn't work the way most folks seem to expect. (It allows math and currency symbols, etc.)

Alternative solution for NOT LIKE clause is:
where REGEXP_LIKE(column, '^[[:digit:]]+$')

Related

SQL Server's ISNUMERIC function

I need to checking a column where numeric or not in SQL Server 2012.
This my case code.
CASE
WHEN ISNUMERIC(CUST_TELE) = 1
THEN CUST_TELE
ELSE NULL
END AS CUSTOMER_CONTACT_NO
But when the '78603D99' value is reached, it returns 1 which means SQL Server considered this string as numeric.
Why is that?
How to avoid this kind of issues?
Unfortunately, the ISNUMERIC() function in SQL Server has many quirks. It's not exactly buggy, but it rarely does what people expect it to when they first use it.
However, since you're using SQL Server 2012 you can use the TRY_PARSE() function which will do what you want.
This returns NULL:
SELECT TRY_PARSE('7860D399' AS int)
This returns 7860399
SELECT TRY_PARSE('7860399' AS int)
https://msdn.microsoft.com/en-us/library/hh213126.aspx
Obviously, this works for datatypes other than INT as well. You say you want to check that a value is numeric, but I think you mean INT.
Although try_convert() or try_parse() works for a built-in type, it might not do exactly what you want. For instance, it might allow decimal points, negative signs, and limit the length of digits.
Also, isnumeric() is going to recognize negative numbers, decimals, and exponential notation.
If you want to test a string only for digits, then you can use not like logic:
(CASE WHEN CUST_TELE NOT LIKE '%[^0-9]%'
THEN CUST_TELE
END) AS CUSTOMER_CONTACT_NO
This simply says that CUST_TELE contains no characters that are not digits.
Nothing substantive to add but a couple warnings.
1) ISNUMERIC() won't catch blanks but they will break numeric conversions.
2) If there is a single non-numeric character in the field and you use REPLACE to get rid of it you still need to handle the blank (usually with a CASE statement).
For instance if the field contains a single '-' character and you use this:
cast(REPLACE(myField, '-', '') as decimal(20,4)) myNumField
it will fail and you'll need to use something like this:
CASE WHEN myField IN ('','-') THEN NULL ELSE cast(REPLACE(myField, '-', '') as decimal(20,4)) END myNumField

Catch exception with isnumeric in sql server

I have this possible values in a column
1
65
5 excellent
54
-1
-
.
If I use isnumeric with the last example I get 1, but when I try to convert to number I got an error. I want to use a try-catch in a function but I can't, how can I deal with this?
By the way, an even worse example is '-.', which isnumeric() considers to be valid.
My advice is to look for at least one digit in the value as well. Yucky, but:
isnumeric(val) and val like '%[0-9]%'
Note that isnumeric() also considers something in exponential notation to be valid. So '8e4' will test as positive. This may not be an issue for you, because it will convert to a valid value. Such matches have caused a problem for me in the past, so I tend to use something like:
val not like '%[^0-9.]%' and val not like '%.%.%' and val like '%[0-9]%'
That is, it only has decimal points and digits. And, it doesn't have two decimal points. But, it only works for positive values.
I think you are looking for something like this:
select case isnumeric('a') when 1 then convert(int,'a') else null end
Could you explain your goal? Something like this could be useful:
SELECT CASE ISNUMERIC(col)
WHEN 1 THEN CAST(col as float) -- or int, decimal, etc.
ELSE NULL -- Or 0, -9999, or whatever value you want to use as "exception" value
END
The TRY…CATCH construct cannot be used in a user-defined function.
http://msdn.microsoft.com/en-us/library/ms175976%28v=SQL.105%29.aspx
If you are working on SQL Server 2012, I recommend using TRY_CONVERT:
select TRY_CONVERT(int, '.') returns NULL instead of an error.

ORA-00932 inconsistent datatypes expected char got number

When I try to execute the query below I get the error:
ORA-00932 inconsistent datatypes expected char got number
select (case when upper (TEXT) <> lower (TEXT) then 'INVALID'
else sum(TEXT)
end)
from CLASS
where SECTION = 'SEVENTH'
The query works fine when I remove SUM in ELSE condition> But I need to SUM the Text to achieve the expected result.
You can't sum a character value and all the returned values in a CASE statement must be the same datatype.
If you transform your SUM to a character using TO_CHAR() this still won't work as you're not grouping correctly, see this SQL Fiddle.
The easiest way to do this would be to return a 0 rather than 'INVALID', sum over the entire case statement and change this back to 'INVALID' if it's 0. It's not quite the same... don't store numbers in character columns?
select case when a = 0 then 'INVALID'
else to_char(a)
end
from ( select sum( case when upper(txt) <> lower(txt) then 0
else to_number(txt)
end ) as a
from class )
Here's a SQL Fiddle to demonstrate.
Well you can't SUM text, right? That's why it works well when you remove the operation from the CASE. Have you tried using to_number on the value you're trying to sum?

Does SQL Server really evaluate every 'then' clause in a case expression?

I'm working with an ItemNumber field in a legacy system that is 99% numbers, but there are a few records that contain letters. The numbers are all padded with leading zeros so I thought I would just cast them as bigint's to solve this problem, but of course it throws an error when it gets to the records with letters in them.
I thought the following case statement would have worked, but it still throws the error. Why in the world is SQL Server evaluating the cast if the isnumeric(itemnumber) = 1 condition isn't true?
select case when isnumeric(itemnumber) = 1
then cast(itemnumber as bigint)
else itemnumber
end ItemNumber
from items
And what's the best workaround?
Your expression tries to convert a VARCHAR value into a BIGINT if it's numeric and leave the value as is if it's not.
Since you are mixing datatypes in the CASE statement, SQL Server tries to cast them all into BIGINT but fails on non-numeric values.
If you just want to omit non-numeric values, get rid of the ELSE clause:
SELECT CASE ISNUMERIC(itemnumber)
WHEN 1 THEN
CAST(itemnumber AS BIGINT)
END
FROM items
Maybe because:
ISNUMERIC returns 1 for some characters that are not numbers, such as plus (+), minus (-), and valid currency symbols such as the dollar sign ($). For a complete list of currency symbols, see money and smallmoney (Transact-SQL).
http://msdn.microsoft.com/en-us/library/ms186272.aspx
The problem is that you are still mixing your types:
select case when isnumeric(itemnumber) = 1
then cast(itemnumber as bigint) --bigint
else itemnumber --varchar or whatever
end ItemNumber --????
from items
You need two columns
select case when isnumeric(itemnumber) = 1
then cast(itemnumber as bigint) --bigint
else -1
end NumericItemNumber
from items
select case when isnumeric(itemnumber) = 1
then ''
else itemnumber
end StringItemNumber
from items
Then you need to build a query that takes both ints and varchars

Access to SQL: IFF function

I have not used access before but I have to convert an access query into SQL so I can write a report in crystal.
The query currently uses the IFF function in its select statement which appears to determine what value will be returned depending on the table's value for a particular column.
So for instance if the value is "CR" it should be returned as "credit" and if it's "NCR" it should be returned as "non-credit"
Can I do something like this in SQL?
Use a CASE expression.
CASE WHEN SomeColumn = 'CR' THEN 'credit'
WHEN SomeColumn = 'NCR' THEN 'non-credit'
END
You can use the CASE statement:
SELECT CASE WHEN [value] = 'CR' THEN 'Credit' WHEN [Value] = 'NCR' THEN 'non-credit' END
In addition to CASE expressions, Oracle database also supports the DECODE() function.
SELECT DECODE(value, 'CR', 'Credit', 'NCR', 'Non-Credit') from table;
There are few cases where it may be useful to use a DECODE() function rather than a CASE expression, but I would recommend sticking with CASE.