isnumeric function not providing expected results - sql

The dsply_val is a varchar(2000) field. When i run the query below i am getting 0 for the isnumeric columns even though these values appear to be numeric. I am trying to perform a simple calculation on this column but I end up getting conversion error when I try to convert to decimal or float. As you can see by the 15.2 value some actually do come back as numeric.
I exported the dsply_val to excel and verified that there are no letters or anything out of the ordinary.
What else could i attempt with this or what am I not doing correctly?
SELECT obsv_cd_name,
dsply_val,
ISNUMERIC(dsply_val),
ISNUMERIC(dsply_val + 'e0'),
ISNUMERIC(rtrim(Ltrim(dsply_val)))
FROM smsmir.mir_sr_obsv
where obsv_cd_name = 'WBC'
and sort_dtime >= '2015-01-25'
and orgz_cd = 'CFVMC'
and dsply_val NOT like ('%SEE%')
WBC 8.6 0 0 0
WBC 7.8 0 0 0
WBC 13.4 0 0 0
WBC 5.9 0 0 0
WBC 8.2 0 0 0
WBC 5.9 0 0 0
WBC 7.5 0 0 0
WBC 15.2 1 1 1
WBC 15.2 0 0 0

I think you have line feed or carriage return or tab char in your column.
Actually I can reproduce your problem:
SET NOCOUNT ON
GO
Set string to 6 + Carriage Return + Line Feed + Tab
DECLARE #s NVARCHAR(MAX) = '6' + CHAR(13) + CHAR(10) + CHAR(9)
You see just 6
SELECT #s
But the length of string is 4:
SELECT LEN(#s)
Here are results for ISNUMERIC function:
SELECT ISNUMERIC(#s)
Even TRIM doesn't help:
SELECT ISNUMERIC(LTRIM(RTRIM(#s)))
You should replace those chars:
SELECT ISNUMERIC(REPLACE(REPLACE(REPLACE(#s, CHAR(10), ''), CHAR(13), ''), CHAR(9), ''))
You can print out all chars in your string, so you can then replace non-digit chars in string with blank '':
DECLARE #i INT = 1
WHILE #i <= len(#s)
BEGIN
PRINT ASCII(SUBSTRING(#s, #i, 1))
SET #i = #i + 1
END

Use this function instead of ISNUMERIC. Trim functionality has been added in the function.
CREATE FUNCTION dbo.isReallyNumeric
(
#num VARCHAR(64)
)
RETURNS BIT
BEGIN
SET #num = LTRIM(RTRIM(#num))
IF LEFT(#num, 1) = '-'
SET #num = SUBSTRING(#num, 2, LEN(#num))
DECLARE #pos TINYINT
SET #pos = 1 + LEN(#num) - CHARINDEX('.', REVERSE(#num))
RETURN CASE
WHEN PATINDEX('%[^0-9.-]%', #num) = 0
AND #num NOT IN ('.', '-', '+', '^')
AND LEN(#num)>0
AND #num NOT LIKE '%-%'
AND
(
((#pos = LEN(#num)+1)
OR #pos = CHARINDEX('.', #num))
)
THEN
1
ELSE
0
END
END
GO
And use the query
SELECT ColumnName
FROM Yourtable
WHERE DBO.isReallyNumeric(ColumnName)=1

Related

SQL Proper Case Function Query Refinement

I have a table of names that I am trying to convert from UPPERCASE to Proper Case. And the below code does almost exactly what I am. When I was testing it out I noticed that I had folks who had Roman Numerals in their name, Mc* and O'* in the table. Naturally the query converted any multiple Roman Numeral into Iv like it was supposed to and any MCDONALDS or O'DANIEL were converted into Mcdonalds and O'daniel. I was trying to figure out how to make a clean change to this function so I can run my update query but I'm still peacemilling my SQL knowledge together in off hours. Any help/suggestions would be much appreciated. I did a google search and found several examples but the ones I tried didn't work. The amount of corrections I would have to do is relatively minor (17 corrections out of 1000 row table), but I'd like to try and tidy it up to limit as many human errors as possible.
Thank you in advance for your help.
CREATE FUNCTION [dbo].[f_ProperCase]
(#Text as varchar(80))
RETURNS varchar(80) as
BEGIN
DECLARE #Reset bit
DECLARE #Ret varchar(80)
DECLARE #i int
DECLARE #c char(1)
SELECT #Reset = 1, #i=1, #Ret = ''
WHILE #i <= LEN(#Text)
SELECT #c= SUBSTRING(#Text,#i,1),
#Ret = #Ret + CASE WHEN #Reset=1 THEN UPPER(#c) ELSE LOWER(#c) END,
#Reset= CASE WHEN
CASE WHEN SUBSTRING(#Text,#i-4,5) like '_[a-z] [DOL]''' THEN 1
WHEN SUBSTRING(#Text,#i-4,5) like '_[a-z] [D][I]' THEN 1
WHEN SUBSTRING(#Text,#i-4,5) like '_[a-z] [M][C]' THEN 1
WHEN SUBSTRING(#Text,#i-4,5) like '_[a-z] [M][c][*]' THEN 1 --Convert MCDONALD to McDonald
WHEN SUBSTRING(#Text,#I-4,5) like '_[a-z] [O][''][*]' THEN 1 --Convert O'DONNEL to O'Donnel
ELSE 0
END = 1
THEN 1
ELSE CASE WHEN #c like '[a-zA-Z]' or #c in ('''') THEN 0
ELSE 1
END
END,
#i = #i +1
RETURN #Ret
end
I would do it differently:
CREATE FUNCTION [dbo].[f_ProperCase]
(#Text as varchar(80))
RETURNS varchar(80) as
BEGIN
DECLARE #Reset bit
DECLARE #Ret varchar(80)
DECLARE #i int
DECLARE #c char(1)
DECLARE #Text1 varchar(81)
SELECT #Reset = 1, #i=1, #Ret = '', #Text1 = ' ' + #Text
WHILE #i <= LEN(#Text1)
SELECT #c= SUBSTRING(#Text1,#i,1),
#Ret = #Ret + CASE WHEN #Reset=1 THEN UPPER(#c) ELSE LOWER(#c) END,
#Reset= CASE WHEN
CASE WHEN SUBSTRING(#Text1,#i-2,3) like ' [DdOoLl]''' THEN 1
WHEN SUBSTRING(#Text1,#i-2,4) like ' [Mm][cC][a-zA-Z]' THEN 1
WHEN SUBSTRING(#Text1,#i-3,5) like ' [Mm][Aa][cC][a-zA-Z]' THEN 1
ELSE 0
END = 1
THEN 1
ELSE CASE WHEN #c like '[a-zA-Z]' or #c in ('''') THEN 0
ELSE 1
END
END,
#i = #i +1
RETURN stuff(#Ret, 1, 1, '')
end
This function supports O', L', D', as well as Mc, and Mac. The function is also converts from any case (not only the upper case) to the proper case
SQL Fiddle
select dbo.f_ProperCase('CORMACK')
,dbo.f_ProperCase('Mcdonald ronald')
,dbo.f_ProperCase('o''hara')
| | | |
|---------|-----------------|--------|
| Cormack | McDonald Ronald | O'Hara |
I tweaked some to handle suffixes being included in the name. This handled almost anything I threw at it. We sometimes had hyphenated names as well as periods after some suffixes. I know handling from I-IX was overkill, but was easy enough to add the X to the V check.
ALTER FUNCTION dbo.udf_ProperCase
(#Text as varchar(1024))
RETURNS varchar(1024)
AS
/*
Created to ProperCase most common LastName (Mc/Mac/O'/D'/L') and handle I(first)-IX(nineteenth) suffixes
Original Code: https://stackoverflow.com/questions/22923616/sql-proper-case-function-query-refinement
SELECT dbo.udf_ProperCase('iitest demetrii mcdonald o''neil victor second 2nd ii iii iv v vi vii viii ix x xi test')
*/
BEGIN
DECLARE #Reset bit
DECLARE #Ret varchar(1024)
DECLARE #i int
DECLARE #c char(1)
DECLARE #Text1 varchar(1025)
SELECT #Reset = 1, #i=1, #Ret = '', #Text1 = ' ' + #Text + ' ' --Ensure one space before to make first char upper and after to handle suffixes
--Loop through each character, comparing prior/next to determine if need to handle
WHILE #i <= LEN(#Text1)
BEGIN
SELECT
#c= SUBSTRING(#Text1,#i,1)
,#Ret = #Ret + CASE WHEN #Reset=1 THEN UPPER(#c) ELSE LOWER(#c) END
,#Reset= CASE
WHEN
CASE
WHEN SUBSTRING(#Text1,#i-2,3) like '[ -][DdOoLl][''`]' THEN 1 --Names (including hyphenated) beginning with D/O/L
WHEN SUBSTRING(#Text1,#i-2,4) like ' [Mm][cC][a-zA-Z]' THEN 1 --Names with Mc
WHEN SUBSTRING(#Text1,#i-3,5) like ' [Mm][Aa][cC][a-zA-Z]' THEN 1 --Names with Mac
WHEN SUBSTRING(#Text1,#i-1,4) like ' [Ii][Ii][ .]' THEN 1 --Handle II (include ending with Space or period)
WHEN SUBSTRING(#Text1,#i-1,5) like ' [Ii][Ii][Ii][ .]' THEN 1 --Handle III
WHEN SUBSTRING(#Text1,#i-2,4) like ' [Ii][Ii][ .]' THEN 1 --Handle II
WHEN SUBSTRING(#Text1,#i-2,5) like ' [Ii][Ii][Ii][ .]' THEN 1 --Handle III
WHEN SUBSTRING(#Text1,#i-3,4) like ' [Ii][Ii][ .]' THEN 1 --Handle II
WHEN SUBSTRING(#Text1,#i-3,5) like ' [Ii][Ii][Ii][ .]' THEN 1 --Handle III
WHEN SUBSTRING(#Text1,#i-1,4) like ' [Ii][VvXx][ .]' THEN 1 --Handle IV
WHEN SUBSTRING(#Text1,#i-1,4) like ' [VvXx][Ii][ .]' THEN 1 --Handle VI
WHEN SUBSTRING(#Text1,#i-1,5) like ' [VvXx][Ii][Ii][ .]' THEN 1 --Handle VII
WHEN SUBSTRING(#Text1,#i-1,6) like ' [VvXx][Ii][Ii][Ii][ .]' THEN 1 --Handle VIII
WHEN SUBSTRING(#Text1,#i-2,4) like ' [VvXx][Ii][ .]' THEN 1 --Handle VI
WHEN SUBSTRING(#Text1,#i-2,5) like ' [VvXx][Ii][Ii][ .]' THEN 1 --Handle VII
WHEN SUBSTRING(#Text1,#i-2,6) like ' [VvXx][Ii][Ii][Ii][ .]' THEN 1 --Handle VIII
WHEN SUBSTRING(#Text1,#i-3,4) like ' [VvXx][Ii][ .]' THEN 1 --Handle VI
WHEN SUBSTRING(#Text1,#i-3,5) like ' [VvXx][Ii][Ii][ .]' THEN 1 --Handle VII
WHEN SUBSTRING(#Text1,#i-3,6) like ' [VvXx][Ii][Ii][Ii][ .]' THEN 1 --Handle VIII
ELSE 0
END = 1 THEN 1
ELSE
CASE
WHEN #c like '[a-zA-Z`]' or #c in ('''') or #c like '[0-9]' THEN 0 --If any letter, single-quote or number, then keep next lowercase
ELSE 1 --Anything else (e.g. Space dash, And(&), etc. make next Upper-Case)
END
END
,#i = #i +1
END
RETURN stuff(#Ret, 1, 1, '')
END
GO

convert the numbers

First I am converting the value from the table as integer like
cast(convert(int, isnull(b.temp,0)) as varchar(500))
and then I would like to output values as written below for example
1 as 001
12 as 012
123 as 123
-1 as -001
-15 as -015
-234 as -234
and if length of the integer value is more than 3 then do not display any value or remove it.
If integer has Minus(-) sign then it is not part of the length
so -001 is consider as length 3
so 001 and -001 is acceptable as length 3
How can I do that?
It looks like you are trying to 0 pad numbers in a range. This is one way I do it:
select (case when val between 0 and 999
then right('000'+cast(<col> as varchar(100)), 3)
when val between -999 and 0
then '-'+right('000'+cast(abs(<col>) as varchar(100)), 3)
else ''
end)
from t
There really is no efficient way to do this, but I understand there are situations where this needs to be done. I would probably go about it with something like this turned into a function.
DECLARE #myInt as INT
SET #myInt = -9
DECLARE #padding AS VARCHAR(1)
SET #padding = '0'
DECLARE #length AS INT
SET #length = 3 - LEN(ABS(#myInt))
DECLARE #result AS VARCHAR(5)
SET #result = REPLICATE(#padding, #length) + cast(ABS(#myInt) as VARCHAR(3))
IF #myInt < 0
SET #result = '-' + #result
SELECT #result
This really should be done in code and not sql.
Solution below works. Thanks
declare #num1 as varchar(50)
set #num1 = '1'
select (case
when #num1 between 0 and 999 then right('000'+cast(#num1 as varchar(100)), 3)
when #num1 between -999 and 0 then '-'+right('000'+cast(abs(#num1) as varchar(100)), 3)
else ''
end) as t

SQL2000 safely cast a VARCHAR(256) to INT

I'm having some problem safely casting a varchar to int on SQL2000.
Part 1 of my problem was that IsNumeric returns false positives if your looking for integers only. I'm aware though why IsNumeric does this though (floats, money etcetera are numeric too) so i looked for an IsInteger function on google.
I found the following User Defined Function (UDF):
CREATE FUNCTION dbo.IsInteger
(
#num VARCHAR(64)
)
RETURNS BIT
BEGIN
IF LEFT(#num, 1) = '-'
SET #num = SUBSTRING(#num, 2, LEN(#num))
RETURN CASE
WHEN PATINDEX('%[^0-9-]%', #num) = 0
AND CHARINDEX('-', #num) <= 1
AND #num NOT IN ('.', '-', '+', '^')
AND LEN(#num)>0
AND #num NOT LIKE '%-%'
THEN
1
ELSE
0
END
END
this seems to do a good job checking for integers:
declare #num varchar(256);
declare #num2 varchar(256);
set #num = '22312311';
set #num2 = '22312311.0';
SELECT #num AS [character],
dbo.IsInteger(#num) AS [isInteger],
CASE dbo.IsInteger(#num)WHEN 1 THEN convert(int, #num) ELSE NULL END AS [integer]
UNION
SELECT #num2 AS [character],
dbo.IsInteger(#num2) AS [isInteger],
CASE dbo.IsInteger(#num2)WHEN 1 THEN convert(int, #num2) ELSE NULL END AS [integer];
However it won't validate if the integer is within range (-2^31 <=> 2^31 - 1)
declare #num varchar(256);
set #num = '2147483648';
SELECT #num AS [character],
dbo.IsInteger(#num) AS [isInteger],
CASE dbo.IsInteger(#num)WHEN 1 THEN convert(int, #num) ELSE NULL END AS [integer];
Which throws
Server: Msg 248, Level 16, State 1, Line 3
The conversion of the nvarchar value '2147483648' overflowed an int column. Maximum integer value exceeded.
SQL2000 doesn't have TRY/CATCH (answer presumes ISNUMERIC() returns no false positives) and casting errors cause the entire batch to fail even within UDF's according to this website:
When an error occurs in a UDF,
execution of the function is aborted
immediately and so is the query, and
unless the error is one that aborts
the batch, execution continues on the
next statement – but ##error is 0!
and even if they didn't would still obscure ##error. I also can't cast to bigint since it might still crash (albeit not as often) and this query is part of a UNION which is output to XML which is further validated and transformed with XSLT by a VB6 COM DLL and displayed on a website coded back in 2001 so I really (no really) do not want to change the query output!.
So this leaves me stuck on this seemingly easy task:
if varchar is castable to int cast to int otherwise give me NULL
Any pointers / solutions would be much apreciated but please note that I can't, under no circumstance, change the source column's datatype nor change the validation when data is entered.
Edit:
You can not have numbers over decimal(38,0) in SQL Server (+/- 10^38 -1) so can not trap them or convert them. Which means 37 characters may length and a CAST to decimal(38,0)
SELECT
CASE
WHEN CAST(MyColumn AS decimal(38,0) BETWEEN -2147483648 AND 2147483647 THEN CAST(MyColumn AS int)
ELSE NULL
END
FROM
MyTable
WHERE
ISNUMERIC(MyColumn + '.0e0') = 1 AND LEN(MyColumn) <= 37
Respect to this article for the .0e0 trick
EDIT OP
This question lead me to the folowing updated IsInteger function.
CREATE FUNCTION dbo.IsInteger
(
#num VARCHAR(256)
)
RETURNS BIT
BEGIN
RETURN CASE
WHEN ISNUMERIC(#num + '.0e0') = 1 AND convert(decimal(38,0), #num) BETWEEN -2147483648 AND 2147483647 THEN 1
ELSE 0
END
END
You could just add a couple more checks into the function:
CREATE FUNCTION [dbo].[IsInteger]
(
#num VARCHAR(64)
)
RETURNS BIT
BEGIN
IF LEFT(#num, 1) = '-'
SET #num = SUBSTRING(#num, 2, LEN(#num))
DECLARE #IsInt BIT
SELECT #IsInt = CASE
WHEN PATINDEX('%[^0-9-]%', #num) = 0
AND CHARINDEX('-', #num) <= 1
AND #num NOT IN ('.', '-', '+', '^')
AND LEN(#num)>0
AND #num NOT LIKE '%-%'
THEN
1
ELSE
0
END
IF #IsInt = 1
BEGIN
IF LEN(#num) <= 11
BEGIN
DECLARE #test bigint
SELECT #test = convert(bigint, #num)
IF #test <= 2147483647 AND #test >= -2147483648
BEGIN
set #IsInt = 1
END
ELSE
BEGIN
set #IsInt = 0
END
END
ELSE
BEGIN
set #IsInt = 0
END
END
RETURN #IsInt
END
I've not had a chance to test but I think it should work - I've left it as verbose as possible

How do I convert an int to a zero padded string in T-SQL?

Let's say I have an int with the value of 1. How can I convert that int to a zero padded string, such as 00000001?
Declare #MyInt integer Set #MyInt = 123
Declare #StrLen TinyInt Set #StrLen = 8
Select Replace(Str(#MyInt, #StrLen), ' ' , '0')
Another way is:
DECLARE #iVal int = 1
select REPLACE(STR(#iVal, 8, 0), ' ', '0')
as of SQL Server 2012 you can now do this:
format(#int, '0000#')
This work for me:
SELECT RIGHT('000' + CAST(Table.Field AS VARCHAR(3)),3) FROM Table
...
I created this user function
T-SQL Code :
CREATE FUNCTION CIntToChar(#intVal Int, #intLen Int) RETURNS nvarchar(24) AS BEGIN
IF #intlen > 24
SET #intlen = 24
RETURN REPLICATE('0',#intLen-LEN(RTRIM(CONVERT(nvarchar(24),#intVal))))
+ CONVERT(nvarchar(24),#intVal) END
Example :
SELECT dbo.CIntToChar( 867, 6 ) AS COD_ID
OUTPUT
000867
Use FORMAT(<your number>,'00000000') use as many zeroes as you need to have digits in your final outcome.
Here is official documentation of the FORMAT function
If I'm trying to pad to a specific total length, I use the REPLICATE and DATALENGTH functions, like so:
DECLARE #INT INT
DECLARE #UNPADDED VARCHAR(3)
DECLARE #PADDED VARCHAR(3)
SET #INT = 2
SET #UNPADDED = CONVERT(VARCHAR(3),#INT)
SET #PADDED = REPLICATE('0', 3 - DATALENGTH(#UNPADDED)) + #UNPADDED
SELECT #INT, #UNPADDED, #PADDED
I used variables here for simplicity, but you see, you can specify the final length of the total string and not worry about the size of the INT that you start with as long as it's <= the final string length.
I always use:
SET #padded = RIGHT('z0000000000000'
+ convert(varchar(30), #myInt), 8)
The z stops SQL from implicitly coverting the string into an int for the addition/concatenation.
If the int can go negative you have a problem, so to get around this I sometimes do this:
DECLARE #iVal int
set #iVal = -1
select
case
when #ival >= 0 then right(replicate('0',8) + cast(#ival as nvarchar(8)),8)
else '-' + right(replicate('0',8) + cast(#ival*-1 as nvarchar(8)),8)
end
Very straight forward way to think about padding with '0's is, if you fixed your #_int's to have 4 decimals, you inject 4 '0's:
select RIGHT( '0000'+ Convert(varchar, #_int), 4) as txtnum
; if your fixed space is 3, you inject 3'0's
select RIGHT( '000'+ Convert(varchar, #_int), 3) as txtnum
; below I inject '00' to generate 99 labels for each bldg
declare #_int int
set #_int = 1
while #_int < 100 Begin
select BldgName + '.Floor_' + RIGHT( '00'+ Convert(varchar, #_int), 2)
+ '.balcony' from dbo.tbl_FloorInfo group by BldgName
set #_int = #_int +1
End
Result is:
'BldgA.Floor_01.balcony'
'BldgB.Floor_01.balcony'
'BldgC.Floor_01.balcony'
..
..
'BldgA.Floor_10.balcony'
'BldgB.Floor_10.balcony'
'BldgC.Floor_10.balcony'
..
..
..
'BldgA.Floor_99.balcony'
'BldgB.Floor_99.balcony'
'BldgC.Floor_99.balcony'
Or if you really want to go hard-core... ;-)
declare #int int
set #int = 1
declare #string varchar(max)
set #string = cast(#int as varchar(max))
declare #length int
set #length = len(#string)
declare #MAX int
set #MAX = 8
if #length < #MAX
begin
declare #zeros varchar(8)
set #zeros = ''
declare #counter int
set #counter = 0
while (#counter < (#MAX - #length))
begin
set #zeros = #zeros + '0'
set #counter = #counter + 1
end
set #string = #zeros + #string
end
print #string
And then there's this one, using REPLICATE:
SELECT REPLICATE('0', 7) + '1'
Of course, you can replace the literals 7 and '1' with appropriate functions as needed; the above gives you your example. For example:
SELECT REPLICATE('0', 8 - LEN(CONVERT(nvarchar, #myInt))) + CONVERT(nvarchar, #myInt)
will pad an integer of less than 8 places with zeros up to 8 characters.
Now, a negative number in the second argument of REPLICATE will return NULL. So, if that's a possibility (say, #myInt could be over 100 million in the above example), then you can use COALESCE to return the number without leading zeros if there are more than 8 characters:
SELECT COALESCE(REPLICATE('0', 8 - LEN(CONVERT(nvarchar, #myInt))) + CONVERT(nvarchar, #myInt), CONVERT(nvarchar, #myInt))
I think Charles Bretana's answer is the simplest and fastest. A similar solution without using STR is:
SELECT REPLACE(REVERSE(
CONVERT(CHAR(5 /*<= Target length*/)
, REVERSE(CONVERT(VARCHAR(100), #MyInt)))
), ' ', '0')

T-SQL trim &nbsp (and other non-alphanumeric characters)

We have some input data that sometimes appears with &nbsp characters on the end.
The data comes in from the source system as varchar() and our attempts to cast as decimal fail b/c of these characters.
Ltrim and Rtrim don't remove the characters, so we're forced to do something like:
UPDATE myTable
SET myColumn = replace(myColumn,char(160),'')
WHERE charindex(char(160),myColumn) > 0
This works for the &nbsp, but is there a good way to do this for any non-alphanumeric (or in this case numeric) characters?
This will remove all non alphanumeric chracters
CREATE FUNCTION [dbo].[fnRemoveBadCharacter]
(
#BadString nvarchar(20)
)
RETURNS nvarchar(20)
AS
BEGIN
DECLARE #nPos INTEGER
SELECT #nPos = PATINDEX('%[^a-zA-Z0-9_]%', #BadString)
WHILE #nPos > 0
BEGIN
SELECT #BadString = STUFF(#BadString, #nPos, 1, '')
SELECT #nPos = PATINDEX('%[^a-zA-Z0-9_]%', #BadString)
END
RETURN #BadString
END
Use the function like:
UPDATE TableToUpdate
SET ColumnToUpdate = dbo.fnRemoveBadCharacter(ColumnToUpdate)
WHERE whatever
This page has a sample of how you can remove non-alphanumeric chars:
-- Put something like this into a user function:
DECLARE #cString VARCHAR(32)
DECLARE #nPos INTEGER
SELECT #cString = '90$%45623 *6%}~:#'
SELECT #nPos = PATINDEX('%[^0-9]%', #cString)
WHILE #nPos > 0
BEGIN
SELECT #cString = STUFF(#cString, #nPos, 1, '')
SELECT #nPos = PATINDEX('%[^0-9]%', #cString)
END
SELECT #cString
How is the table being populated? While it is possible to scrub this in sql a better approach would be to change the column type to int and scrub the data before it's loaded into the database (SSIS). Is this an option?
For large datasets I have had better luck with this function that checks the ASCII value. I have added options to keep only alpha, numeric or alphanumeric based on the parameters.
--CleanType 1 - Remove all non alpanumeric
-- 2 - Remove only alpha
-- 3 - Remove only numeric
CREATE FUNCTION [dbo].[fnCleanString] (
#InputString varchar(8000)
, #CleanType int
, #LeaveSpaces bit
) RETURNS varchar(8000)
AS
BEGIN
-- // Declare variables
-- ===========================================================
DECLARE #Length int
, #CurLength int = 1
, #ReturnString varchar(8000)=''
SELECT #Length = len(#InputString)
-- // Begin looping through each char checking ASCII value
-- ===========================================================
WHILE (#CurLength <= (#Length+1))
BEGIN
IF (ASCII(SUBSTRING(#InputString,#CurLength,1)) between 48 and 57 AND #CleanType in (1,3) )
or (ASCII(SUBSTRING(#InputString,#CurLength,1)) between 65 and 90 AND #CleanType in (1,2) )
or (ASCII(SUBSTRING(#InputString,#CurLength,1)) between 97 and 122 AND #CleanType in (1,2) )
or (ASCII(SUBSTRING(#InputString,#CurLength,1)) = 32 AND #LeaveSpaces = 1 )
BEGIN
SET #ReturnString = #ReturnString + SUBSTRING(#InputString,#CurLength,1)
END
SET #CurLength = #CurLength + 1
END
RETURN #ReturnString
END
If the mobile could start with a Plus(+) I will use the function like this
CREATE FUNCTION [dbo].[Mobile_NoAlpha](#Mobile VARCHAR(1000))
RETURNS VARCHAR(1000)
AS
BEGIN
DECLARE #StartsWithPlus BIT = 0
--check if the mobile starts with a plus(+)
IF LEFT(#Mobile, 1) = '+'
BEGIN
SET #StartsWithPlus = 1
--Take out the plus before using the regex to eliminate invalid characters
SET #Mobile = RIGHT(#Mobile, LEN(#Mobile)-1)
END
WHILE PatIndex('%[^0-9]%', #Mobile) > 0
SET #Mobile = Stuff(#Mobile, PatIndex('%[^0-9]%', #Mobile), 1, '')
IF #StartsWithPlus = 1
SET #Mobile = '+' + #Mobile
RETURN #Mobile
END