Error cast varchar as decimal - sql-server

I have this query in SQL Server 2008:
select ID,CAST(replace(SUBSTRING(LTRIM([value]),1,8)+'.'+SUBSTRING(LTRIM([value]),9,7),',','.')AS DECIMAL (16,7)),
from T1
This is returning cast error.
To find where is the problem I tried the following:
select ID,SUBSTRING(LTRIM([value]),1,8)+'.'+SUBSTRING(LTRIM([value]),9,7),
isnumeric(SUBSTRING(LTRIM([value]),1,8)+'.'+SUBSTRING(LTRIM([value]),9,7))
from T1
where isnumeric(SUBSTRING(LTRIM([value]),1,8)+'.'+SUBSTRING(LTRIM([value]),9,7))<>1
But it returns 0 rows, then I guess that all the values are feasible to cast them to decimal but when I run the first query it fails.
Am I missunderstanding something that creates the problem?
P.D: Value is varchar datatype.

If you were using 2012 then you can use Try_Convert()
However there is a way to get this to work with 2008 by using a CASE statement. This works because CASE stops evaluating when it finds a match.
Here's a simple example for Varchar to Int but you can easily adapt it for Decimal.
CASE WHEN [value] LIKE '%[^0-9]%' THEN [value]
ELSE Convert(varchar(20), CAST([value] as INT))
END

Related

SQL CAST with ISNULL results in conversionfailure

I've got a nullable column of numbers, which is unfortunately declared as a varchar in the database, and so I want to convert the NULL to 0. Doing this accomplishes that.
select ISNULL(col, '0') from table;
So now there are no null possibilities, and then I want to convert the column to an actual int value, so I tried to wrap that.
select CAST(ISNULL(col, '0') AS INT) from table
When that runs I get a conversion error, as shown below. I don't understand why, or how to get around this:
Conversion failed when converting the varchar value 'NULL' to data type int.
Try like this: Take your ISNULL statement outside
SELECT ISNULL(TRY_CAST(col AS INT),0) AS [col]
FROM SAMPLE_TAB;
If this does not help, then please comment your SQL version.

Using Sum(Cast(Replace syntax

I am trying to write a simple query in order to change some of our stage data. I have a varchar $ column (unfortunately) that needs to be summed. My issue is that because of commas, I cannot change the datatype.
So, I can use REPLACE(AMT,',','') to remove the commas but It still wont let me cast it as a decimal and I get
Error converting data type varchar to numeric.
I am trying the following below with no luck. Any ideas? Can this be done or am I using the wrong syntax here?
Select SUM(Cast(REPLACE(Amt,',','') as Decimal (18,2)) )
I was able to resolve this with #HABO suggestion. I used Cast(Ltrim(rtrim(table.AMT)) as Money) for all instances of the varchar amount. This removed white space and removed the commas from the numbers.
This should work... including an example.
Edit: if you are on SQL Server 2012+, you may be able to shorten your task by using Try_Convert
DECLARE #SomeTable AS TABLE (Amt Varchar(100));
INSERT INTO #Sometable (Amt) VALUES ('abc123,456.01'),(' 123,456.78 '),(Null),('asdad'),('');
With NumericsOnly AS
(
SELECT
REPLACE(Left(SubString(Amt, PatIndex('%[0-9.-,]%', Amt), 8000), PatIndex('%[^0-9.,-]%', SubString(Amt, PatIndex('%[0-9.,-]%', Amt), 8000) + 'X')-1),',','') AS CleanAmt
FROM
#SomeTable
)
SELECT
SUM(CONVERT(DECIMAL(18,2), CleanAmt)) AS TotalAmt
FROM
NumericsOnly
WHERE
IsNumeric(CleanAmt)=1
General methodology is taken from here
I wouldn't use money as a data type as it is notorious for rounding error.
The error is due to SQL order of operations within your SUM(CAST(REPLACE... operation. This issue can be resolved by summing the column AFTER it's been staged to be summed via a subquery:
SELECT SUM(Field),...
FROM ( SELECT
Cast(REPLACE(Amt,',','') as NUMERIC) as 'Field'
,...
) [Q]
If the table you're summing is administered by a BI Team, get them to stage the data there. Happy Data Happy life.

Using a CASE statement in ORDER BY clause with different data types

I want to use a CASE statement in my ORDER BY clause as follows:
DECLARE #SortOr TINYINT
SELECT #SortOr = 1
SELECT *
FROM [Table]
ORDER BY CASE WHEN #SortOr = 1 THEN col1
ELSE col2
END
But it throws an error:
Cannot convert varchar into tinyint.
What is the logic behind that? How can fix it?
The underlying issue that #Damien_The_Unbeliever states perfectly in the comments is:
A single CASE expression has to produce values of one data type. So if you have THENs that produce values of different data types, the system uses the precedence rules to decide which ones to convert.
You can replicate your CASE statement to work around this, where each CASE returns a single value/data type. This would be better than converting all values to VARCHAR as suggested in the other answer, which should also perform better (you will have to test):
So new ORDER BY clause will look like:
ORDER BY CASE WHEN #SortOr = 1 THEN col1
END ,
CASE WHEN #SortOr != 1 THEN col2
END -- If you need DESC it goes after END
Convert all returned values by the CASE statement to VARCHAR and it will work.
SQL Server tries to convert all your returned values implicitly, because they are part of the same expression and SQL Server wants them really to be the same type; it tries to convert to INT, because INT has higher precedence than VARCHAR; so you should set the same type for this explicitly.

ms sql server executes 'then' before 'when' in case

when i try to select
select
case when (isnumeric(SUBSTRING([VZWECK2],1,9)) = 1)
then CONVERT(decimal,SUBSTRING([VZWECK2],1,9))
else null
end as [NUM]
from table
sql-server gives me:
Msg 8114, Level 16, State 5, Line 2
Error converting data type varchar to numeric.
[VZWECK2] is a char(27). is this a known bug? because it seems to me it executes the convert before it does the case, which defies the purpose of my select. i know that there are values that are not numeric obviously, which is why i need the case statement to weed them out.
for some reason selecting
select
case when (isnumeric(SUBSTRING([VZWECK2],1,9)) = 1)
then 99
else null
end as [NUM]
from table
yields no errors and behaves as expected
The problem is that ISNUMERIC is very forgiving, and that ISNUMERIC returns 1 is unfortunately no guarantee that CONVERT will work. This is why SQL Server 2012 and later introduced TRY_CAST and TRY_CONVERT.
If you are converting whole numbers, a more reliable check is to make sure the string consists of only digits with NOT LIKE '%[^0-9]%' (that is, it must not contain a non-digit anywhere). This is too restrictive for some formats (like floating point) but for integers it works nicely.
Do you know the value which throws the error? IsNumeric is not exactly fool-proof, for example:
select ISNUMERIC('$')
select ISNUMERIC('+')
select ISNUMERIC('-')
all yield 1
Alternatively, you could go with TRY_PARSE instead.
Edit: TRY_PARSE is introduced in sql server 2012, so may not be available to you.

Problem convert column values from VARCHAR(n) to DECIMAL

I have a SQL Server 2000 database with a column of type VARCHAR(255). All the data is either NULL, or numeric data with up to two points of precision (e.g. '11.85'). I tried to run the following T-SQL query but received the error 'Error converting data type varchar to numeric'
SELECT CAST([MyColumn] AS DECIMAL)
FROM [MyTable];
I tried a more specific cast, which also failed.
SELECT CAST([MyColumn] AS DECIMAL(6,2))
FROM [MyTable];
I also tried the following to see if any data is non-numeric, and the only values returned were NULL.
SELECT ISNUMERIC([MyColumn]), [MyColumn]
FROM [MyTable]
WHERE ISNUMERIC([MyColumn]) = 0;
I tried to convert to other data types, such as FLOAT and MONEY, but only MONEY was successful. So I tried the following:
SELECT CAST(CAST([MyColumn] AS MONEY) AS DECIMAL)
FROM [MyTable];
...which worked just fine. Any ideas why the original query failed? Will there be a problem if I first convert to MONEY and then to DECIMAL?
Thanks!
It's likely that this depends on whether the decimal symbol is a comma or a dot. Here are some test queries and their results:
select CAST('3.6' as decimal) -- 3.60
select CAST('3,6' as decimal) -- Error converting data type varchar to numeric.
select CAST('3.6' as money) -- 3.60
select CAST('3,6' as money) -- 36.00 (!)
select ISNUMERIC('3.6') -- 1
select ISNUMERIC('3,6') -- 1
The documentation for ISNUMERIC says :
ISNUMERIC returns 1 when the input
expression evaluates to a valid
integer, floating point number, money
or decimal type; otherwise it returns
0
Both 3.6 and 3,6 can be cast to money, so that's why isnumeric('3,6') returns 1.
To resolve this issue, replace the comma's with dots (or vice versa, if your system uses comma as the decimal symbol):
select cast(replace('3,6',',','.') as decimal)
Another option is to change the "decimal symbol" in Windows. It's in Config Panel -> Regional and Language -> Formats -> Additional Settings -> Numbers.
Another cause is empty strings. For example, if you use the import wizard to import a CSV file, empty fields will become empty strings, not nulls.
This is a common idiom for fixing this:
CAST(NULLIF([number_as_a_string],'') AS decimal(13,2))
Select CAST(isnull(MyColumn,0) as Decimal(4,2))
FROM [MyTable];

Resources