How to convert Varchar column to Numeric - sql

I have a requirement to move varchar column data to Numeric but with two conditions.
All the alphanumeric value should migrate as null
All the decimal values should go as it is.
I wrote the condition as WHERE data like '%[^0-9]%', it is working fine for all the records except for decimal.
Also I have values like .001 abcd, this has to be pass as null.
To summarize I need :
1) 1234 as 1234
2) 1.23 as 1.23
3) ABC as null
4) .ABC as null

There is by default function in SQL Server ISNUMERIC() so, first of all Check your data value by that function,
Select ISNUMERIC(DATA)
Whole query is written as below,
SELECT CASE WHEN ISNUMERIC(data)=1 THEN CAST(data as decimal(18,2))
ELSE NULL END as tData FROM DataTable
As per your question,first we have to convert with numeric with using case,which satisfies your first condition,another thing if the value is String than convert as NULL. In Above query both the condition has been taken care.
EDIT : If you are using SQL SERVER 2012 or higher version then use
TRY_PARSE(), then there will be no need to worry about using CASE too...
I have tried this,
SELECT TRY_PARSE('63.36' as decimal(18,2)) got result 63.36
and
SELECT TRY_PARSE('.' as decimal(18,2)) got result NULL

I think that this fits your spec. It is quite verbose, but hopefully it breaks down the conditions sufficiently that it's clearly doing the correct thing or, if it isn't, that it's easy enough to modify:
declare #t table (data varchar(30))
insert into #t(data) values
('1234'),
('1.23'),
('abc'),
('.abc'),
('+6000'),
('1.2.3')
select
CASE WHEN
Possible = 1 AND
(DecCheck = 0 OR
SingleDec = 1
) THEN
CONVERT(decimal(12,3),data)
END
from
#t t
cross apply
(select
--Only contains the correct characters
CASE WHEN not t.data like '%[^0-9.]%' THEN 1 ELSE 0 END as Possible,
--Contains a decimal point? (Needs more checks)
CASE WHEN CHARINDEX('.',t.data) > 0 THEN 1 ELSE 0 END as DecCheck,
CHARINDEX('.',t.data) as FirstDec --Where the first decimal point is
) p
cross apply
(select
CASE WHEN DecCheck = 1 THEN
--Only contains one decimal point
CASE WHEN LEN(data) = FirstDec + CHARINDEX('.',REVERSE(data)) - 1
THEN 1
ELSE 0 END
ELSE 0 END as SingleDec
) d
Results:
data
------------------------------ ---------------------------------------
1234 1234.000
1.23 1.230
abc NULL
.abc NULL
+6000 NULL
1.2.3 NULL
I.e. one additional check you may want to use is that a decimal cannot be the first or last character in the string. That is easy enough to do by adding those additional checks into the first CASE for the SingleDec column.

try ISNUMERIC function,
SELECT ISNUMERIC('abc')
SELECT ISNUMERIC('1.23')

On SQL Server (Version 2012, 11.0.5343)
SELECT
CASE WHEN ISNUMERIC('.') = 1 THEN <Field> ELSE 0 END
FROM
<Table>
works fine ...

Thre is A blog post.
Try following
SELECT
CASE
WHEN
ISNUMERIC(data + 'e0') = 1 THEN CAST(data AS decimal(18,2))
ELSE NULL END AS tData
FROM
DataTable

try ISNUMERIC function
DECLARE #MyTable TABLE(Val VARCHAR(100))
INSERT INTO #MyTable
VALUES
('1234')
,('1.23')
,('ABC')
,('.ABC')
,('MJA')
Select Val as OldValue,
Case
When ISNUMERIC(Val) = 1
then Cast(Val as numeric(18,2))
else null
end NewValue
From #MyTable
Output
OldValue NewValue
-----------------------------------------------------
1234 1234.00
1.23 1.23
ABC NULL
.ABC NULL
MJA NULL
(5 row(s) affected)

Related

CAST, SUM, CASE Issues

I am trying to accommodate for some rogue values in my database, that contain the string 'unknown', I want to set these to 0 and then sum the rest. But for some reason, this isnt happening. Here is what I have -
Values - VARCHAR(30) -
3
0.1
2
16
2
5
2
Unknown
2.4
7
Unknown
And here is my Cast,Sum,Case
Cast(sum(case when stake = 'Unknown' then 0 else stake end) as float) as totalStake
But I get this error - Conversion failed when converting the varchar value '0.1' to data type int.
Help!
Thanks
You must cast stake as a float:
sum(case when stake = 'Unknown' then 0.0 else cast(stake as float) end) as totalStake
You should explicitly convert to some sort of numeric values. Try this:
sum(try_convert(numeric(18, 4), stake)) as totalStake
Your code has at least two issues. First, your case expression returns an integer (because the first then has an integer). So, it tries to convert stake to an integer, which can generate an error.
Second, you should be doing arithmetic operations on data that is explicitly some sort of number type and not rely on implicit conversion.
You can try the following query using isnumeric() to check numeric data.
create table temp (stake VARCHAR(30))
insert into temp values
('3'), ('0.1'), ('2'), ('16'), ('2'), ('5'), ('2'), ('Unknown'), ('2.4'), ('7'), ('Unknown')
--Select * from temp
Select sum(Cast(stake as Float)) from temp where isnumeric(stake) = 1
To handle some exception like null values or . values only you can try this
Select SUM(TRY_CAST(stake as Float)) from temp
You can find the live demo Here.
Initial step would be to replace the 'Unknown' string with 0 using a replace function and then convert the column datatype to the one which allows to perform Aggregate functions and then perform SUM on top of that. The below query will work only for 'unknown' string, if you have different strings other than 'unknown' you might have to choose a different approach like using IsNumeric in Replace function and update the string value to 0.
select sum(cast((REPLACE(stake,'unknown',0)) as float)) from table
This happens because SQL has some problems while converting decimal values to integer values.
In facts, function sum returns integer values
I solved it using round function on the values1 variable ( sorry for using same name for table and column ):
select Cast(sum(case when values1 = 'Unknown' then 0 else round(values1, 2) end) as
float)as totalstrike
from values1

ISNUMERIC and TRY_PARSE in SQL Server [duplicate]

What is the best way to determine whether or not a field's value is an integer in SQL Server (2000/2005/2008)?
IsNumeric returns true for a variety of formats that would not likely convert to an integer. Examples include '15,000' and '15.1'.
You can use a like statement but that only appears to work well for fields that have a pre-determined number of digits...
select * where zipcode like '[0-9][0-9][0-9][0-9][0-9]'
I could write a user defined function that attempts to convert a varchar parameter to an int within a try/catch block but I'm checking with the community to see if someone has come across any succient methods to achieve this goal - preferably one that can be used within the where clause of a SQL statement without creating other objects.
Late entry that handles negative
ISNUMERIC(zipcode + '.0e0') --integer
ISNUMERIC(zipcode + 'e0') --decimal
For more see this
1 approach is
zipcode NOT LIKE '%[^0-9]%'
Double negatives, got to love 'em!
If SQL Server 2005+, I'd enable CLR and create the function to support regexes. For SQL Server 2000, see this article for creating a UDF to do the same thing.
Then I'd use the regex: ^\d{5}$
This expression gives 1 for an integer value and 0 otherwise
floor((floor(abs(zipcode)))/abs(zipcode))
Why not just use the following? I can't see to find any cases where it fails.
1 = integer
0 = not integer
null = non-numeric
DECLARE #TestValue nvarchar(MAX)
SET #TestValue = '1.04343234e5'
SELECT CASE WHEN ISNUMERIC(#TestValue) = 1
THEN CASE WHEN ROUND(#TestValue,0,1) = #TestValue
THEN 1
ELSE 0
END
ELSE null
END AS Analysis
It looks like this question needs an updated answer.
Limiting the answer to the question title:
where ISNUMERIC(zipcode) = 1
and zipcode - FLOOR(zipcode) = 0
Expounding based on the text of the question...
Currently-supported versions of SQL Server all support/include the TRY-CONVERT function.
declare #a varchar(100)
set #a = '-1.2a'
--set #a = '-1.2'
--set #a = '-1'
--set #a = '-1.0'
--set #a = '-0'
--set #a = '0'
--set #a = '1'
select #a as 'Value'
, ISNUMERIC(#a) as ISNUMERIC
, case when ISNUMERIC(#a) = 1 and #a - FLOOR(#a) = 0 then 1 else 0 end as ISINTEGER
, case when try_convert(int, #a) >= 0 and left(#a, 1) <> '-' then 1 else 0 end as ISWHOLENUMBER
, case when try_convert(int, #a) > 0 then 1 else 0 end as ISCOUNTINGNUMBER
You'll notice that TRY_CONVERT(INT, -1.0) returns NULL. So TRY_CONVERT(INT, #a) IS NOT NULL is not quite right for ISINTEGER.
case when ISNUMERIC(#a) = 1 and #a - FLOOR(#a) = 0 then 1 else 0 end as ISINTEGER
...works because if ISNUMERIC(#a) = 1 is false, FLOOR(#a) is not evaluated. Reversing the order...
case when #a - FLOOR(#a) = 0 and ISNUMERIC(#a) = 1 then 1 else 0 end as ISINTEGER
...generates an error when the value (#a) is not numeric.
So, for the case of zipcode, assuming you want to verify that a 5-digit zip code is a number and it must be 5 digits (so it can't be zero or less) and would never contain a decimal point (so you don't need to know if 12345.000 is an integer):
where try_convert(int, zipcode) > 0
and len(zipcode) = 5
I came up with the perfect answer for this on another StackO question.
It also proves you cannot use ".0e0" like one user suggests here.
It does so without CLR or non-scalar functions.
Please check it out: https://stackoverflow.com/a/10645764/555798
After moving to sql 2008, I was struggling with isnumeric('\8') returning true but throwing an error when casting to an integer. Apparently forward slash is valid currency for yen or won - (reference http://www.louiebao.net/blog/200910/isnumeric/)
My solution was
case when ISNUMERIC(#str) > 0 and not rtrim(#str) LIKE '[^0-9]%' and not rtrim(#str) LIKE '%[^0-9]' and not rtrim(#str) LIKE '[^0-9]%' then rtrim(#str) else null end
See whether the below code will help.
In the below values only 9, 2147483647, 1234567 are eligible as
Integer. We can create this as function and can use this.
CREATE TABLE MY_TABLE(MY_FIELD VARCHAR(50))
INSERT INTO MY_TABLE
VALUES('9.123'),('1234567'),('9'),('2147483647'),('2147483647.01'),('2147483648'), ('2147483648ABCD'),('214,7483,648')
SELECT *
FROM MY_TABLE
WHERE CHARINDEX('.',MY_FIELD) = 0 AND CHARINDEX(',',MY_FIELD) = 0
AND ISNUMERIC(MY_FIELD) = 1 AND CONVERT(FLOAT,MY_FIELD) / 2147483647 <= 1
DROP TABLE MY_TABLE
I did it using a Case statement:
Cast(Case When Quantity/[# of Days]= Cast(Quantity/[# of Days] as int) Then abs(Quantity/[# of Days]) Else 0 End as int)
To test whether the input value is an integer or not we can use SQL_VARIANT_PROPERTY function of SQL SERVER.
The following SQL Script will take input and test it whether the data type turns out to be integer or not
declare #convertedTempValue bigint, #inputValue nvarchar(255) = '1' --Change '1' to any input value
set #convertedTempValue = TRY_PARSE(#inputValue as bigint) --we trying to convert to bigint
declare #var3 nvarchar(255) = cast (SQL_VARIANT_PROPERTY(#convertedTempValue,'BaseType') as nvarchar(255)) --we using SQL_VARIANT_PROPERTY to find out datatype
if ( #var3 like '%int%')
begin
print 'value is integer'
end
else
begin
print 'value is non integer'
end
go
Really late to this but would this work?
select * from from table
where (ISNUMERIC(zipcode) = 0 OR zipcode like '%.%')
Filters out items that are integers.
Maybe you should only store integer data in integer datatypes.

Remove only zero after decimal sql server 2012

Consider the following numbers.
7870.2
8220.0
I need to remove decimal points if the value ends with .0. If it ends with .2 then it should keep the value as it is.
I have used ceiling but it removes all the values after decimal.
How can I write a select query in which I can add some condition for this?
Generally speaking you should not do this in your dB. This is an app or reporting side operation. The dB is made to store and query information. It is not made to format/string manipulate information.
use right within a case statement and:
DECLARE #val decimal(5,1)
SET #val = 7870.0
Select
Case
When right(#val,1)<> '0' then
cast(#val as varchar)
else
cast(cast(#val as int) as varchar)
End
output: 7870
EDIT: I could write :
Case
When right(#val,1)<> '0' then
#val
else
cast(#val as int) -- or floor(#val)
End
but because return type of case statement is the highest precedence type from the set of given types, so the output for second version is: 7870.0 not 7870, that's why I convert it to i.e varchar in when clauses, and it can be converted outside of case statement, I mean cast ((case when...then...else... end) as datatype)
Cast the number as a float, using float(24) to increase precision:
DECLARE #t table(number decimal(10,1))
INSERT #t values(7870.2),(8220.0)
SELECT cast(number as float(24))
FROM #t
Result:
7870,2
8220
Here below goes a sample:
declare #1 decimal(4,3)
select #1 = 2.9
select case when SUBSTRING (PARSENAME(#1,1), 1, 1) = 0 then FLOOR(#1) else #1 end
Change the #1 in the select statement with your database field name.
sqlfiddle
The solution seems to be simple:
SELECT CONVERT (FLOAT, PAYLOAD)

SQL query: convert

I'm trying to read a column from a database using a SQL query. The column consists of empty string or numbers as strings, such as
"7500" "4460" "" "2900" "2640" "1850" "" "2570" "9050" "8000" "9600"
I'm trying to find the right sql query to extract all the numbers (as integers) and removing the empty ones, but I'm stuck. So far I've got
SELECT *
FROM base
WHERE CONVERT(INT, code) IS NOT NULL
Done in program R (package sqldf)
If all columns are valid integers, you could use:
select * , cast(code as int) IntCode
from base
where code <> ''
To prevent cases when field code is not a valid number, use:
select *, cast(codeN as int) IntCode
from base
cross apply (select case when code <> '' and not code like '%[^0-9]%' then code else NULL end) N(codeN)
where codeN is not null
SQL Fiddle
UPDATE
To find rows where code is not a valid number, use
select * from base where code like '%[^0-9]%'
select *
from base
where col like '[1-9]%'
Example: http://sqlfiddle.com/#!6/f7626/2/0
If you don't need to test for the number being valid, ie. a string such as '909XY2' then this may run marginally faster, more or less depending on the size of the table
Is this what you want?
SELECT (case when code not like '%[^0-9]%' then cast(code as int) end)
FROM base
WHERE code <> '' and code not like '%[^0-9]%';
The conditions are repeated in the where and case on purpose. SQL Server does not guarantee that where filters are applied before logic in the select, so you can get an error with conversions. More recent versions of SQL Server have try_convert() to fix this problem.
Using sqldf with the default sqlite database and this test data:
DF <- data.frame(a = c("7500", "4460", "", "2900", "2640", "1850", "", "2570",
"9050", "8000", "9600"), stringsAsFactors = FALSE)
try this:
library(sqldf)
sqldf("select cast(a as aint) as aint from DF where length(a) > 0")
giving:
aint
1 7500
2 4460
3 2900
4 2640
5 1850
6 2570
7 9050
8 8000
9 9600
Note In plain R one could write:
transform(subset(DF, nchar(a) > 0), a = as.integer(a))

Best equivalent for IsInteger in SQL Server

What is the best way to determine whether or not a field's value is an integer in SQL Server (2000/2005/2008)?
IsNumeric returns true for a variety of formats that would not likely convert to an integer. Examples include '15,000' and '15.1'.
You can use a like statement but that only appears to work well for fields that have a pre-determined number of digits...
select * where zipcode like '[0-9][0-9][0-9][0-9][0-9]'
I could write a user defined function that attempts to convert a varchar parameter to an int within a try/catch block but I'm checking with the community to see if someone has come across any succient methods to achieve this goal - preferably one that can be used within the where clause of a SQL statement without creating other objects.
Late entry that handles negative
ISNUMERIC(zipcode + '.0e0') --integer
ISNUMERIC(zipcode + 'e0') --decimal
For more see this
1 approach is
zipcode NOT LIKE '%[^0-9]%'
Double negatives, got to love 'em!
If SQL Server 2005+, I'd enable CLR and create the function to support regexes. For SQL Server 2000, see this article for creating a UDF to do the same thing.
Then I'd use the regex: ^\d{5}$
This expression gives 1 for an integer value and 0 otherwise
floor((floor(abs(zipcode)))/abs(zipcode))
Why not just use the following? I can't see to find any cases where it fails.
1 = integer
0 = not integer
null = non-numeric
DECLARE #TestValue nvarchar(MAX)
SET #TestValue = '1.04343234e5'
SELECT CASE WHEN ISNUMERIC(#TestValue) = 1
THEN CASE WHEN ROUND(#TestValue,0,1) = #TestValue
THEN 1
ELSE 0
END
ELSE null
END AS Analysis
It looks like this question needs an updated answer.
Limiting the answer to the question title:
where ISNUMERIC(zipcode) = 1
and zipcode - FLOOR(zipcode) = 0
Expounding based on the text of the question...
Currently-supported versions of SQL Server all support/include the TRY-CONVERT function.
declare #a varchar(100)
set #a = '-1.2a'
--set #a = '-1.2'
--set #a = '-1'
--set #a = '-1.0'
--set #a = '-0'
--set #a = '0'
--set #a = '1'
select #a as 'Value'
, ISNUMERIC(#a) as ISNUMERIC
, case when ISNUMERIC(#a) = 1 and #a - FLOOR(#a) = 0 then 1 else 0 end as ISINTEGER
, case when try_convert(int, #a) >= 0 and left(#a, 1) <> '-' then 1 else 0 end as ISWHOLENUMBER
, case when try_convert(int, #a) > 0 then 1 else 0 end as ISCOUNTINGNUMBER
You'll notice that TRY_CONVERT(INT, -1.0) returns NULL. So TRY_CONVERT(INT, #a) IS NOT NULL is not quite right for ISINTEGER.
case when ISNUMERIC(#a) = 1 and #a - FLOOR(#a) = 0 then 1 else 0 end as ISINTEGER
...works because if ISNUMERIC(#a) = 1 is false, FLOOR(#a) is not evaluated. Reversing the order...
case when #a - FLOOR(#a) = 0 and ISNUMERIC(#a) = 1 then 1 else 0 end as ISINTEGER
...generates an error when the value (#a) is not numeric.
So, for the case of zipcode, assuming you want to verify that a 5-digit zip code is a number and it must be 5 digits (so it can't be zero or less) and would never contain a decimal point (so you don't need to know if 12345.000 is an integer):
where try_convert(int, zipcode) > 0
and len(zipcode) = 5
I came up with the perfect answer for this on another StackO question.
It also proves you cannot use ".0e0" like one user suggests here.
It does so without CLR or non-scalar functions.
Please check it out: https://stackoverflow.com/a/10645764/555798
After moving to sql 2008, I was struggling with isnumeric('\8') returning true but throwing an error when casting to an integer. Apparently forward slash is valid currency for yen or won - (reference http://www.louiebao.net/blog/200910/isnumeric/)
My solution was
case when ISNUMERIC(#str) > 0 and not rtrim(#str) LIKE '[^0-9]%' and not rtrim(#str) LIKE '%[^0-9]' and not rtrim(#str) LIKE '[^0-9]%' then rtrim(#str) else null end
See whether the below code will help.
In the below values only 9, 2147483647, 1234567 are eligible as
Integer. We can create this as function and can use this.
CREATE TABLE MY_TABLE(MY_FIELD VARCHAR(50))
INSERT INTO MY_TABLE
VALUES('9.123'),('1234567'),('9'),('2147483647'),('2147483647.01'),('2147483648'), ('2147483648ABCD'),('214,7483,648')
SELECT *
FROM MY_TABLE
WHERE CHARINDEX('.',MY_FIELD) = 0 AND CHARINDEX(',',MY_FIELD) = 0
AND ISNUMERIC(MY_FIELD) = 1 AND CONVERT(FLOAT,MY_FIELD) / 2147483647 <= 1
DROP TABLE MY_TABLE
I did it using a Case statement:
Cast(Case When Quantity/[# of Days]= Cast(Quantity/[# of Days] as int) Then abs(Quantity/[# of Days]) Else 0 End as int)
To test whether the input value is an integer or not we can use SQL_VARIANT_PROPERTY function of SQL SERVER.
The following SQL Script will take input and test it whether the data type turns out to be integer or not
declare #convertedTempValue bigint, #inputValue nvarchar(255) = '1' --Change '1' to any input value
set #convertedTempValue = TRY_PARSE(#inputValue as bigint) --we trying to convert to bigint
declare #var3 nvarchar(255) = cast (SQL_VARIANT_PROPERTY(#convertedTempValue,'BaseType') as nvarchar(255)) --we using SQL_VARIANT_PROPERTY to find out datatype
if ( #var3 like '%int%')
begin
print 'value is integer'
end
else
begin
print 'value is non integer'
end
go
Really late to this but would this work?
select * from from table
where (ISNUMERIC(zipcode) = 0 OR zipcode like '%.%')
Filters out items that are integers.
Maybe you should only store integer data in integer datatypes.