Issue with IsNumeric in t-sql? - sql-server

Below is some test SQL. IsNumeric is saying the substring of 05031, is numeric, but fails when it tries to convert it to an actual number because of the ,. Is this a bug in SQL?
DECLARE #Str NVARCHAR(20)
SET #Str = 'XYZ 505031, some text'
SELECT CASE WHEN ISNUMERIC(SUBSTRING(#Str,6,7)) = 1 THEN CONVERT(int,SUBSTRING(#Str,6,7)) ELSE 0 END, SUBSTRING(#Str,6,7)

you should use try_cast instead, because ISNUMERIC evaluates to 1 for 5031,
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).
DECLARE #Str NVARCHAR(20)
SET #Str = 'XYZ 505031, some text'
SELECT
CASE
WHEN TRY_CAST(SUBSTRING(#Str,6,7) AS DECIMAL(10,2)) IS NOT NULL
THEN CONVERT(int,SUBSTRING(#Str,6,7))
ELSE 0
END,
SUBSTRING(#Str,6,7)

If 2012+, you can use Try_Convert(). We use MONEY becase the this will convert the leading zero, and then we convert to int
Example
DECLARE #Str NVARCHAR(20)
SET #Str = 'XYZ 505031, some text'
SELECT AsInt = IsNull(try_convert(int,try_convert(money,SUBSTRING(#Str,6,7))),0)
, AsStr = SUBSTRING(#Str,6,7)
Returns
AsInt AsStr
5031 05031,

This is because your substring is also pulling a comma in the end.
SELECT SUBSTRING(#Str, 6, 7);
is resulting:
05031,
Whereas,
SELECT SUBSTRING(#Str, 6, 5);
is resulting:
05031
And
SELECT CASE WHEN ISNUMERIC(SUBSTRING(#Str,6,5)) = 1 THEN CONVERT(int,SUBSTRING(#Str,6,5)) ELSE 0 END, SUBSTRING(#Str,6,5)
is resulting:
5031 | 05031

Related

Max Value in split XML using SQL Server

Anyone able to advice why does my max value return smaller value?
DECLARE #SalesYear as nvarchar(max),
#SalesPeriod as nvarchar(max)
SET #SalesYear = 2020
SET #SalesPeriod = '5,6,7,8,10'
BEGIN
DECLARE #Split char(1)=',',
#X xml
SELECT #X = CONVERT(xml, ' <root> <myvalue>' +
REPLACE(#SalesPeriod,#Split,'</myvalue> <myvalue>') + '</myvalue> </root>')
IF (OBJECT_ID('tempdb..#breakdown') IS NOT NULL)
BEGIN
DROP TABLE #breakdown
END
SELECT T.c.value('.','varchar(20)') breakdown
INTO #breakdown
FROM #X.nodes('/root/myvalue') T(c)
END
SELECT MAX(breakdown)
FROM #breakdown
It returns max value as '8' instead of '10'. Anything wrong with my code?
I would change the type INT instead of varchar as SalesPeriod seems have a numerical values :
SELECT T.c.value('.','INT') AS breakdown INTO #breakdown
FROM #X.nodes('/root/myvalue') T(c)
So, string value comparisons 8 will be higher than 10, You can check :
select case when '8' > '10' then 1 else 0 end
If you change the type (remove quotes), you will see right flagging. So, i would recommend to use appropriate datatype.

Conversion failed when converting the varchar value '$400,000.00' to data type int

I have the following part of query that works fine:
CONVERT(varchar(15), CONVERT(money, AmountOfInsurance), 1) AS AmountOfInsurance
I want to prevent anounts that are equal to 0 to show up formated, just to show up: 0, so I added this CASE statement but I get the following error:
CASE WHEN AmountOfInsurance > 0 THEN '$' + CONVERT(varchar(15), CONVERT(money, AmountOfInsurance), 1) ELSE 0 END AS AmountOfInsurance
Any idea?
Your ELSE should be '' because you want to return a varchar. Now the CASE expression has two data types and INT takes precedence over varchar, that's why it tries to convert the varchar back to INT.
Added for reference:
Data Type Precedence
Just another option (if 2012+) is Format() with a conditional format.
Declare #YourTable table (AmountOfInsurance money)
Insert Into #YourTable values
(400000),
(2500),
(0)
Select format(AmountOfInsurance,IIF(AmountOfInsurance>0,'$#,##0.00','0'))
From #YourTable
Returns
$400,000.00
$2,500.00
0
Use the CAST function to cast
DECLARE #text AS NVARCHAR(10)
SET #text = '100$'
SELECT CASE WHEN AmountOfInsurance > 0 THEN CAST(#text AS MONEY) ELSE 0 END

Comma in number with decimal point in SQL Server 2008

I want to put comma in numbers for varchar type with single decimal point with no roundup.
For example:
DECLARE #val varchar(50) = '12345.999'
I want result as :
12,345.9
So far I have tried:
select convert(VARCHAR(15), cast(#val as money), 1)
Result: 12,346.00
but it is doing rounding the value.
Please help. Thanks in advance.
DECLARE #val varchar(50) = '12345.999'
SELECT LEFT(CONVERT(VARCHAR(15),CAST(#val AS MONEY),1),CHARINDEX('.',#val)-3) + SUBSTRING(#val,CHARINDEX('.',#val)-3,5)
Perhaps this will work. Just use the LEFT() function a couple of times after casting to MONEY and VARCHAR
DECLARE #val VARCHAR(50) = '12345.99999'
SELECT LEFT(CONVERT(VARCHAR(15),CAST(LEFT(#val,
CHARINDEX('.',#val,1)+1) AS MONEY),1),CHARINDEX('.',#val,1)+2)
Result:
12,345.9
** Edit **
After thinking about the possibility of having a larger number for the variable, it wouldn't work when there are multiple commas i.e., 123,412,345.999 so I'm editing to include a CASE statement:
DECLARE #val VARCHAR(50) = '123412345.99999'
SELECT LEFT( CONVERT(VARCHAR(15),
CONVERT(MONEY
,LEFT(#val, CHARINDEX('.',#val,1)+1)
,1)
,1)
, CHARINDEX('.',#val)+(CASE
WHEN LEN(LEFT(#val, CHARINDEX('.',#val)-1))>6 THEN 3
ELSE 2
END))

Unable to add string at the end using STUFF

I tried to Insert a string within another string using STUFF.
DECLARE #Number VARCHAR(100) = '12345'
SELECT STUFF(#Number, 3, 0, '6') -- Add value in 3rd Position, Returns '126345'
I tried to append the value at the end
SELECT STUFF(#Number, 6, 0, '6') -- Add value in 6th Position
-- Actual length is 5, So it Returns 'NULL'
Expected Output:
123456
I tried using STUFF for simple statement. But not able to append string at the end. Can anyone help me to do in any other simple way?
From here:
The second paramter is an integer value that specifies the location to
start deletion and insertion. If start or length is negative, a null
string is returned. If start is longer than the first
character_expression, a null string is returned. start can be of type
bigint.
This query :
DECLARE #Number VARCHAR(100) = '12345'
SELECT STUFF(#Number, 6, 0, '6')
return NULL because there is only 5 characters.
If you want append string at the end just concat that string using + operator.
DECLARE #Number VARCHAR(100) = '12345'
SELECT #Number + '6'
You can use CONCAT to append strings one after the other. They will be appended in the order in which they are passed to the function:
DECLARE #Number VARCHAR(100) = '12345'
select concat(#Number,'6')
You can also use the '+' operator for this purpose. However, if one the strings being appended is NULL, the result will also be NULL using '+', whereas the NULL string is treated as a blank string by CONCAT.
select concat(#Number,null,6) -- = '123456'
select #Number + null + 6 -- == null
If the position to insert is not fixed, you can use a CASE statement along with STUFF and CONCAT to either insert into or append in a single statement, like so:
declare #number varchar(100) = '12345'
declare #pos int = 6
declare #append varchar(100) = '6'
select
case
when #pos < len(#number) then stuff(#number,#pos,0,#append)
else concat(#number,#append)
end result
As a hack you can do this,
SELECT STUFF(#Number, 5, 1, '56')

How to get MAX value of numeric values in varchar column

I have a table with a nvarchar column. This column has values for example:
983
294
a343
a3546f
and so on.
I would like to take MAX of this values, but not as text but like from numerics. So in this example numerics are:
983
294
343
3546
And the MAX value is the last one - 3546. How to do this in TSQL on Microsoft SQL?
First install a regular expression function. This article has code you can cut/paste.
Then with RegexReplace (from that article) you can extract digits from a string:
dbo.RegexReplace( '.*?(\d+).*', myField, '$1' )
Then convert this string to a number:
CAST( dbo.RegexReplace( '.*?(\d+).*', myField, '$1' ) AS INT )
Then use this expression inside a MAX() function in a SELECT.
You can try to keep it simple without using Regular Expression
Here is the source
create table #t ( val varchar(100) )
insert #t select 983
insert #t select 294
insert #t select 'a343'
insert #t select 'a3546f';
GO
;with ValueRange as (
select val,
[from] = patindex('%[0-9]%', val),
[to] = case patindex('%[a-z]', val)
when 0 then len(val)
else patindex('%[a-z]', val) - patindex('%[0-9]%', val)
end
from #t
)
select substring(val, [from], [to]) as val
from ValueRange VR
order by cast(substring(val, [from], [to]) as int) desc
CAST() would do the trick, probably.
SELECT MAX(CAST(yourColumn AS int)) AS maxColumns FROM yourTable
Edit.
I didn't read the whole question, as it seems...
– Function to strip out non-numeric chars
ALTER FUNCTION dbo.UDF_ParseNumericChars
(
#string VARCHAR(8000)
)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE #IncorrectCharLoc SMALLINT
–SET #IncorrectCharLoc = PATINDEX(’%[^0-9A-Za-z]%’, #string)
SET #IncorrectCharLoc = PATINDEX(’%[^0-9.]%’, #string)
WHILE #IncorrectCharLoc > 0
BEGIN
SET #string = STUFF(#string, #IncorrectCharLoc, 1, ”)
SET #IncorrectCharLoc = PATINDEX(’%[^0-9.]%’, #string)
END
SET #string = #string
RETURN #string
END
GO
I picked it from here. (I voted up the reg exp answer though)
you can write a function something like
create FUNCTION [dbo].[getFirstNumeric](
#s VARCHAR(50)
)
RETURNS int AS
BEGIN
set #s = substring(#s,patindex('%[0-9]%',#s),len(#s)-patindex('%[0-9]%',#s) + 1)
if patindex('%[^0-9]%',#s) = 0
return #s
set #s = substring(#s,1,patindex('%[^0-9]%',#s)-1)
return cast(#s as int)
end
and then call
select max(dbo.getFirstNumeric(yourColumn)) from yourTable
if you are using SQL Server 2005 or never you can also use the solution posted by Sung Meister
As far as I know you would need to create a process (or user defined function) to scrub the column, so that you can actually convert it to an INT or other appropriate datatype, then you can take the max of that.
By using user defined function parse the value to an int and then run the select.
SELECT MAX(dbo.parseVarcharToInt(column)) FROM table
SELECT dbo.RegexReplace('[^0-9]', '','a5453b',1, 1)
and RegexReplace installation like Jason Cohen said
This is an old question, I know - but to add to the knowledge base for others...
Assuming all your values have at least 1 number in them:
Select max(convert(int, SubString(VarName, PATINDEX('%[0-9]%',VarName), Len(VarName))))
from ATable
This is my simple answer. You can try it. But it works for fixed removable string value.
select max(cast(SUBSTRING(T.column,3,len(T.column)) as int)) from tablename T

Resources