Casting Scientific Notation (from varchar -> numeric) in a view - sql

For reasons I can not help I have a varchar column with data like the following: 820.0E-12, 10.0E+00.
I want the numeric value. So I have this test query which works:
declare #d varchar(256)
set #d = '820.0E-12'
select
CASE
WHEN #d like '%E-%' THEN LTRIM(RTRIM(CAST(CAST(#d AS FLOAT) AS DECIMAL(18,18))))
WHEN #d like '%E+%' THEN NULL
ELSE #d
END
My result is: 0.000000000820000000 (which is what I want)
I change my SQL to account for the numbers > 0 (10.0E+00) like this:
WHEN #d like '%E+%' THEN CAST(#d AS FLOAT)
My result changes to: 8.2E-10 (which is NOT what I want)
If I change #d='10.0E+00' then I get 10 (which is correct).
I've got a view that I need to make the output from a varchar column, that contains scientific notation, casted/converted into decimal(18,18).
Can somebody tell me what craziness is going on here?
Or, maybe my question should be, how do I cast/convert a varchar scientific notation column to decimal output in a view?
My first WHEN statement works for numbers < 0 but I also need to account for numbers > 0. When I change the second WHEN, to include the CAST, it breaks/gives the wrong result.

There's a couple different problems all coming together here at the same time. Let's look at some of them:
You're casting numbers as DECIMAL(18, 18). What that means is "give me a number that has room for a TOTAL of 18 characters, and 18 of them should be after the decimal". That works fine as long as your number is smaller than 0 (which is true for all E- numbers) but it will break if you try to use it on numbers > 0. For numbers > 0, just cast as DECIMAL without specifying anything else.
In the case where you add "WHEN #d like '%E+%' THEN CAST(#d AS FLOAT)", you're getting different results for numbers < 0 because the engine is implicitly casting the result differently. I don't know the rules on how sql server decides to cast CASE results, but apparently making your proposed change causes the engine to recast it in a different way. Explicitly casting those results as decimal fixes the issue.
You need to LTRIM and RTRIM your results consistently. You can either add LTRIM and RTRIM to each case statement, or you can just LTRIM and RTRIM the results of the case.
Here's a solution that should totally solve everything:
SELECT
LTRIM(RTRIM(CASE
WHEN #d like '%E-%' THEN CAST(CAST(#d AS FLOAT) AS DECIMAL(18,18))
WHEN #d like '%E+%' THEN CAST(CAST(#d AS FLOAT) AS DECIMAL)
ELSE #d
END))

you can use ISO "real" datatype
SELECT convert(numeric(18,18),convert(real,'820.0E-12'))
--OR with more precision
SELECT convert(numeric(18,18),convert(float(53),'820.0E-12'))

select CAST(cast('2.74E-05' as float) as numeric(10,6))

Related

Conversion from INT to varchar in sql

I have a table where there are values like 20170730 and also 0 values are there which is INT type
I am trying to convert it to value like 30/07/2017, for which i am using the below code,
Select convert(NVARCHAR(10),convert(date,convert(NCHAR(8),datecolumn)),103) from table
But for the zero values i am getting the below error
Conversion failed when converting date and/or time from character string.
If i delete all the zero this working fine but problem having with zero.
My requirement is to convert when there a date value and if 0 are there then it should be zero only like below,
Result
30/07/2017
0
Can u pls help
As already pointed out in the comments, you can try to use a CASE expression
SELECT CASE
WHEN nmuloc = 0 THEN
'0'
ELSE
convert(varchar(10),
convert(date,
convert(varchar(8),
nmuloc),
112),
103)
END
FROM elbat;
or try_convert() and coalesce().
SELECT coalesce(convert(varchar(10),
try_convert(date,
convert(varchar(8),
nmuloc),
112),
103),
'0')
FROM elbat;
db<>fiddle
The latter one will also correct other "malformed" data like 123 for example. The former will also fail in such cases. You may want that or not.
But, as also already pointed out in the comments, your real problem is that you use an inappropriate data type. Change the column's datatype to some date/time data type to really fix this.

SQL Server - Value passes ISDATE() but fails to CAST as DATE or DATETIME

I have a varchar column in my database table, on the row I would like to return it is populated as '2018-12-26T00:00:00.000' (quotes mine, not included in actual value). When I try to query for this value whenever it is a valid date, e.g.
SELECT
myValue
FROM
myTable
WHERE
ISDATE(myValue) = 1
it returns properly. However, I need this value to be converted to DATE. When I try something like this:
SELECT
CAST(myValue AS DATE) AS myValueFormatted
FROM
myTable
WHERE
ISDATE(myValue) = 1
I get an error
Conversion failed when converting date and/or time from character string
Is there any other way I can convert this varchar value to Date?
UPDATE: I've noticed through trying some different things, the query seems to be fine with me using the value as a date for anything (DATEDIFF, CONVERT back to string, etc.) in the select portion, but trying to do anything with it in the WHERE clause causes the error. To ensure nothing else is interfering, I created a temp table with only 1 row with the data value above, and running the query just against that one value gives the error
UPDATE 2: Ok, I have no idea why this fixes it, but this is what I found. When I run
SELECT
myValue
FROM
myTable
WHERE
TRY_CONVERT(DATE, myValue) IS NOT NULL
it returns EXACTLY the same values as
SELECT
myValue
FROM
myTable
WHERE
ISDATE(myValue) = 1
However, when I then add AND CAST(myValue AS DATE) < GETDATE() to each WHERE clause, only the first one works. I understand why TRY_CONVERT is safer to use, I'm still not sure why it works over GETDATE()
I can't reproduce your error...
declare #dt varchar(256) = '2018-12-26T00:00:00.000'
select cast(#dt as date)
So, there must be another rogue value in there that can't be converted.
To identify what value is causing the issue on versions < 2012, run this:
SELECT
myValue
FROM myTable
WHERE
ISDATE(myValue) = 0
Note, ISDATE is deterministic only if you use it with the CONVERT function, if the CONVERT style parameter is specified, and style is not equal to 0, 100, 9, or 109.
For 2012 onward, use TRY_CONVERT
SELECT
*
FROM myTable
WHERE
TRY_CONVERT(date, myValue) IS NULL
You could also just try something like this:
SELECT CAST(LEFT(MyValue, 10) AS DATE)
If it still doesn't work, you have some formatting issues with your data.
This helped me....
CAST string as varchar(30) then cast the varchar as datetime2
CAST(CAST(REPLACE(['Timestamp' ],'''','') AS varchar(30)) as datetime2)

Remove decimal using SQL query

I want to convert my decimal SQL query result in percent. Example I have a 0.295333 I want it to be 30% and if I have a 0.090036 I want it to be 9%.
This is what I have so far.
(100 * (sample1/ sample2) ) as 'Percent'
I also tried this one but the problem is result comes with ".00" and I don't know how to remove the decimal.
cast (ROUND(100 * (sample1 / sample2),0) As int ) as 'Percent'
Try with the below script..
cast (100 * Round((sample1 / sample2),2) As int ) as 'Percent'
So as some of the comments pointed out you may need to pay attention to your datatype if one or both of the original columns that you get your decimal from are integer.
One easy way of dealing with that is something like this:
ColA * ColB * 1.0 which will make sure that your integers are treated as decimals
So if you have SQL Server 2012+ you can use Format and not mess with rounding at all. Like this FORMAT(YourDecimal,'#%'), yep that simple.
;WITH cteValues AS (
SELECT 0.295333 as OriginalValue
UNION ALL
SELECT 0.090036 as OriginalValue
)
SELECT
OriginalValue
,FORMAT(OriginalValue,'#%') as PercentFormat
FROm
cteValues
If you are pre 2012 and do not have format an easy way is to round to the 100th then times by 100 and cast as int CAST(ROUND(YourDecimal,2) * 100 AS INT)
;WITH cteValues AS (
SELECT 0.295333 as OriginalValue
UNION ALL
SELECT 0.090036 as OriginalValue
)
SELECT
OriginalValue
,CAST(ROUND(OriginalValue,2) * 100 AS INT) as PercentInt
FROm
cteValues
Because an INT cannot by definition have decimal places, if you are receiving .00 with the method similar to this or the one you have tried, I would ask the following.
Are you combining (multiplying etc.) the value after casting with another column or value that may be decimal, numeric, or float?
Are you looking at the query results in a program outside of SSMS that could be formatting the results automatically, e.g. Excel, Access?
Address your assumptions first.
How does ROUND work? Does it guarantee return values and if so, how? What is the precedence of the two columns? Does Arithmetic operators influence the results and how?
I only know what I do not know, and any doubt is worth an investigation.
THE DIVIDEND OPERATOR
Since ROUND always returns the higher precedence, this is not the problem. It is in fact the divide operator ( / ) that may be transforming your values to an integer.
Always verify the variables are consistently of one datatype or CAST if either unsure or unable to guarantee (such as insufficiently formatted. I.e. DECIMAL(4,2) instead of required DECIMAL(5,3) ).
DECLARE #Sample1 INT
, #Sample2 DECIMAL(4,2);
SET #Sample1 = 50;
SET #Sample2 =83.11;
SELECT ROUND( 100 * #Sample1 / #Sample2 , 0 )
Returns properly 60.
SELECT ROUND( 100 * #Sample2 / #Sample1 , 0)
Incorrectly turns variables into integers before rounding.
The reason is that DIVIDE - MSDN in SQL may return the higher precedence, but any dividend that is an integer returns another integer.
UPDATE
This also explains why the decimal remains after ROUND...it is of higher precedence. You can add another cast to transform the non-INT datatype to the preferred format.
SELECT CAST( ROUND( <expression>, <Length>) AS INT)
Note that in answering your question I learned something myself! :)
Hope this helps.

tSQL - Conversion from varchar to numeric works for all but integer

I have a table with numbers in a varchar(255) field. They're all greater than one and have multiple decimal places. I'd like to convert them to integers. According to every web site I've consulted, including this one on StackOverflow, either of these should work:
SELECT CAST(VarcharCol AS INT) FROM MyTable
SELECT CONVERT(INT, VarcharCol) FROM MyTable
These both work for me for every kind of numeric value but integer - I can convert to float, decimal, etc. just fine, but trying to convert to integer gives me the following error:
Conversion failed when converting the varchar value '7082.7758172'
to data type int.
I've worked around the problem by converting to data type Decimal(6,0), which works fine. But just for my education, can anyone tell me why converting to data type int (or integer) gives me an error? Thanks.
Converting a varchar value into an int fails when the value includes a decimal point to prevent loss of data.
If you convert to a decimal or float value first, then convert to int, the conversion works.
Either example below will return 7082:
SELECT CONVERT(int, CONVERT(decimal(12,7), '7082.7758172'));
SELECT CAST(CAST('7082.7758172' as float) as int);
Be aware that converting to a float value may result, in rare circumstances, in a loss of precision. I would tend towards using a decimal value, however you'll need to specify precision and scale values that make sense for the varchar data you're converting.
Actually whether there are digits or not is irrelevant. The . (dot) is forbidden if you want to cast to int. Dot can't - logically - be part of Integer definition, so even:
select cast ('7.0' as int)
select cast ('7.' as int)
will fail but both are fine for floats.
Presumably, you want to convert values before the decimal place to an integer. If so, use case and check for the right format:
SELECT (case when varcharcol not like '%.%' then cast(varcharcol as int)
else cast(left(varcharcol, chardindex('.', varcharcol) - 1) as int)
end) IntVal
FROM MyTable;
Try this
declare #v varchar(20)
set #v = 'Number'
select case when isnumeric(#v) = 1 then #v
else #v end
and
declare #v varchar(20)
set #v = '7082.7758172'
select case when isnumeric(#v) = 1 then #v
else convert(numeric(18,0),#v) end
Try this query:
SELECT cast(column_name as type) as col_identifier FROM tableName WHERE 1=1
Before comparing, the cast function will convert varchar type value to integer type.
SELECT
convert(numeric(18,5),Col1), Col2
FROM DBname.dbo.TableName
WHERE isnumeric(isnull(Col1,1)) <> 0

SQL IsNumeric Returns True but SQL Reports 'Conversion Failed'

Assuming the following data:
Column1 (data type: varchar(50))
--------
11.6
-1
1,000
10"
Non-Numeric String
I have a query, which is pulling data from this column and would like to determine if the value is a number, then return it as such in my query. So I am doing the following
SELECT CASE
WHEN IsNumeric(Replace(Column1, '"', '')) = 1 THEN Replace(Column1, '"', '')
ELSE 0
END AS NumericValue
SQL is reporting back:
Conversion failed when converting the varchar value '11.6' to data type int.
Why? I have also tried to force cast this:
SELECT CASE
WHEN IsNumeric(Replace(Column1, '"', '')) = 1 THEN cast(Replace(Column1, '"', '') AS float)
ELSE 0
END AS NumericValue
And I got:
Error converting data type varchar to float.
You need to replace comma with a period:
CAST(REPLACE(column, ',', '.') AS FLOAT)
SQL Server outputs decimal separator defined with locale, but does not unterstand anything but a period in CASTs to numeric types.
First convert the string to money, then covert it to any other numeric format since money type gives a true numeric string always. You will never see an error then.
Try the following in your query, and you'll know what I am talking about. Both will return 2345.5656. The Money datatype is rounded to 4 decimal places, and hence the casting causes rounding to 4 decimal places.
SELECT CAST('2,345.56556' as money), CAST('$2,345.56556' as money)
Cast( cast('2,344' as money) as float) will work perfectly or
cast( cast('2,344' as money) as decimal(7,2)) will also work.
Even cast(CAST('$2,345.56556' as money) as int ) will work perfectly rounding it to nearest integer.
There are many issues with SQL isnumeric. For example:
select isnumeric('1e5')
This will return 1 but in many languages if you try to convert it to a number it will fail. A better approach is to create your own user defined function with the parameters you need to check for:
http://www.tek-tips.com/faqs.cfm?fid=6423
ISNUMERIC returns 1 when the input expression evaluates to a valid integer, floating point number, money or decimal type;
So the problem is it is a valid number but not a valid int.
Kyle,
I think this solves the problem. The problem lies in the fact that the ELSE clause initializes your result to be an INTEGER. By making an explicit typecast to FLOAT and adding the suggestion of Quassnoi, it seems to work.
DECLARE #MyTable TABLE (Column1 VARCHAR(50))
INSERT INTO #MyTable VALUES('11.6')
INSERT INTO #MyTable VALUES('-1')
INSERT INTO #MyTable VALUES('1,000')
INSERT INTO #MyTable VALUES('10" ')
INSERT INTO #MyTable VALUES('Non-Numeric String')
SELECT CASE WHEN ISNUMERIC(REPLACE(Column1,'"','')) = 1 THEN REPLACE(REPLACE(Column1,'"',''), ',', '.') ELSE CAST(0 AS FLOAT) END
FROM #MyTable
Regards,
Lieven
IsNumeric(' ') also returns 1, but then CAST as int blows up. Brendan above says write your own function. He is correct.
This solution does not work in all cases (specifically numbers with money and/or thousand separators). Concatenate an exponent representation to the end of the number which is represented by a string...ISNUMERIC() works fine from there. Examples below:
-- CURRENT ISNUMERIC RESULTS
SELECT ISNUMERIC('11.6'); --1
SELECT ISNUMERIC ('-1'); --1
SELECT ISNUMERIC('1,000'); --1
SELECT ISNUMERIC('10"'); --0
SELECT ISNUMERIC('$10'); --1
-- NEW ISNUMERIC RESULTS
SELECT ISNUMERIC('11.6'+'e+00'); --1
SELECT ISNUMERIC ('-1'+'e+00'); --1
SELECT ISNUMERIC('1,000'+'e+00'); --0
SELECT ISNUMERIC('10"'+'e+00'); --0
SELECT ISNUMERIC('$10'+'e+00'); --0
This, at the very least, standardizes the format for using the REPLACE() function.
I have just meet this issue.
You can try this solution if you don't mind about limitation of decimal length.
CONVERT(numeric, CONVERT(money, '.'))
NOTE:
It is supported in SQL Server 2008 or above.
Money range is : -922,337,203,685,477.5808 to 922,337,203,685,477.5807 - four decimals.