MSSQL Server 2008 - Convert Nvarchar to numeric - sql

im using mssql 2008 and Im permanently failing to convert an nvarchar to numeric values.
Can you please advise? I have different solutions I found over the www, but all of them are failing with the error message:
Msg 8114, Level 16, State 5, Line 15 Error converting data type
nvarchar to numeric.
I have built an reduced example for demonstration purpose:
IF OBJECT_ID('tempdb..#temptable', 'U') IS NOT NULL
DROP TABLE dbo.#temptable
create table #temptable(
col1 nvarchar(10),
col2 numeric(10,5)
)
insert into #temptable values ('0,5','0')
select *,convert(numeric(18,2),col1) from #temptable
UPDATE #temptable
SET col2 = CAST(col1 AS numeric(10,5))
WHERE ISNUMERIC(col1) = 1
SELECT col1
, CASE ISNUMERIC(col1)
WHEN 1 THEN CONVERT(numeric(18,2),col1)
ELSE 0.00
END
from #temptable

I alreay found an strong hint whats going wrong... the issue seems to be related to the , as seperator while the SQL server expects an .
if you change the following line to:
insert into #temptable values ('0.5','0')
its working

The problem is you are using ISNUMERIC(col1) = 1 which fails for a ton of cases like ISNUMERIC('1e4') or ISNUMERIC('$') or in your case, ISNUMERIC('1,000,000'). Don't use ISNUMERIC in this fashion.
Instead, try this...
UPDATE #temptable
SET col2 = CAST(col1 AS numeric(10,5))
WHERE col1 not like '%[^0-9.]%'

Use try_convert() in SQL Server 2012+:
UPDATE #temptable
SET col2 = TRY_CONVERT(numeric(10,5), col1)
WHERE ISNUMERIC(col1) = 1;
SQL Server re-arranges expression valuation in a query. So, the CAST() might be implemented before the WHERE -- resulting in the error. You can make a similar change to the SELECT version of your query.
In SQL Server 2008, you should be able to do effectively the same thing using CASE:
UPDATE #temptable
SET col2 = (CASE WHEN ISNUMERIC(col1) = 1 THEN CONVERT(numeric(10, 5), col1) END)
WHERE ISNUMERIC(col1) = 1;
Note: There may be cases where ISNUMERIC() returns "1", but the value cannot be converted (for instance, overflow). In that case, this version would still fail.

Related

Separating UNIQUEIDENTFIER values from possible varchars in datamapping

I'm having hard time to differentiate between 'UNIQUEIDENTIFIER' & 'varchar' in a data mapping script. Its a mismatch of data.
I tried this so far:
--my_field is a UNIQUEIDENTFIER
SELECT distinct my_field, len(my_field), count(my_field)
FROM my_table_
WHERE len(my_field) < 36 OR len(my_field) > 36
group by my_field
SELECT my_field, len(my_field)
FROM my_table_
WHERE my_field LIKE '%[!#%&+,./:;<=>#`{|}~"()*\\\_\^\?\[\]\'']%' {ESCAPE '\'}
Any help would be much appreciated.
Assuming your SQL Server version is 2012 or higher (and if not, you really should upgrade, since 2012 is the earliest version still supported by Microsoft) - you can use try_cast - it will return null if the cast fails:
Sample data:
DECLARE #T AS TABLE
(
my_field varchar(100)
)
INSERT INTO #T (my_field) VALUES
('608DC3C3-1B2E-47AA-9362-33CD76DA3F6A'), ('A3871EA9-172D-49DD-8874-A850857F01FB'),
('A3871EA9-THIS-IS-WRONG-A850857F01FB'), ('And so is this')
Query:
SELECT my_field
FROM #T
WHERE TRY_CAST(my_Field AS UNIQUEIDENTIFIER) IS NULL
Result:
my_field
A3871EA9-THIS-IS-WRONG-A850857F01FB
And so is this

SQL Round if numerical?

(Beginner at sql)
I've been getting the error
'Error converting data type nvarchar to float.'
Which is because I was trying to round an nvarchar(10) column with both characters and integers, and obviously it can't round the characters. (I can't make two separate columns with different data types as they both need to be in this column)
I'm looking for a way to round the numbers in the nvarchar column whilst also returning the characters
I've being trying CAST/Converts nothing seems to work
I've also tried
CASE WHEN ISNUMERIC(Tbl1.Column1) = 1
THEN cast(Round(Tbl1.Column1, 0) AS float)
ELSE Tbl1.Column1 END AS 'Column1'
in the select statement
I cant figure out what else will solve this!
Sample Data in this column would be
8.1
2
9.0
9.6
A
-
5.3
D
E
5.1
-
I would go for try_convert() instead of isnumeric():
COALESCE(CONVERT(VARCHAR(255), TRY_CONVERT(DECIMAL(10, 0), Tbl1.Column1)),Tbl1.Column1) as Column1
A conversion problem arises with your approach because a case expression returns a single value. One of the branches is numeric, so the return type is numeric -- and the conversion in the else fails.
You can fix your version by converting the then clause to a string after converting to a float.
since you hold both types in this column, you need to cast your rounded value back to varchar
declare #Tbl1 table (Column1 varchar(10))
insert into #Tbl1 (Column1) values ('8.1'), ('2'), ('9.0'),
('9.6'), ('A'), ('5.3'),
('D'), ('E'), ('5.1'), ('-')
select case when TRY_CONVERT(float, Column1) IS NULL then Column1
else cast(cast(Round(Column1, 0) as float) as varchar(10))
end AS 'Column1'
from #Tbl1
outcome is
Column1
-------
8
2
9
10
A
5
D
E
5
-
In case you get the error TRY_CONVERTis not a build-in function then you have your database compatibility level is less that SQL 2012.
You can correct that using this command
ALTER DATABASE your_database SET COMPATIBILITY_LEVEL = 120;
Also note that after this statement the answer of Gordon is working now, and I agree that is a better answer then mine

SQL Server - Convert String to float with N/A's present

I have a flat file that I loaded into SQL Server using the import wizard. All columns are stored as nchar(50).
I'm now trying to convert the table to a new table with various types (char, float, int, etc).
There is one column that I'd like to convert to float but it contains N/A strings.
I checked that there weren't any other weird string using this:
SELECT col1, count(*)
from tab1
where ISNUMERIC(col1) <> 1
group by col1
Then I wrote a CASE statement to do the conversion:
SELECT CASE WHEN col1 = 'N/A' THEN NULL ELSE CAST(col1 AS FLOAT) END col1
INTO tab2
FROM tab1
But I'm getting this error message:
Msg 8114, Level 16, State 5, Line 1
Error converting data type nvarchar to float.
Any idea what's causing this?
If 2012+ Use try_convert()
SELECT col1, count(*)
from tab1
where try_convert(float,col1) is null
group by col1
You can use try_convert if you want to ignore invalid chars to float as below
Select try_convert(float, col1) as col1 from yourtable
Careful on using ISNUMERIC() for this. It can return some false positives. For example...
select isnumeric('$')
select isnumeric('1e4')
This should show you what is causing the error.
select * from table where column like '%[^0-9\.]%' escape '\'
You can use this in a where clause, or use TRY_CONVERT()
You aren't doing the type conversion from the String to the float. In your SQL statements you need to explicitly cast the original column type from nvarchar to float. Something like this might work:
SELECT
CASE
WHEN col1 = 'N/A' THEN NULL
ELSE CAST(col1 AS FLOAT)
END col1
INTO tab2
FROM tab1

How to safely convert a varchar(255) to an int?

I was using a column in a case expression and it was working fine on server1. When I ran it on server2 it was failing because the column had the value 'false' in it.
The column is a varchar(255), but in my case expression I was using it as if it was an INT type. It worked fine but now it is failing because of the 'false' value in server2.
How can I safely convert to an INT, and if the conversion fails, default to 0.
Is this possible?
My query looks like:
UPDATE t1
set
c1 = ISNULL(
(
SELECT CASE c2
WHEN 123 then 'hello'
WHEN 234 then 'bye'
ELSE ''
END
)
, '')
FROM table1 as t1
There are quite a few ways to convert from numeric to varchar, but none of them are available to you (really, SQLServer2008 is disappointing because it's lacking just a few cool features that are nearly required).
In your case, the best way to do is it simply to convert your numeric expression to varchar like this :
UPDATE t1
set c1 = CASE c2
WHEN '123' then 'hello'
WHEN '234' then 'bye'
ELSE ''
END
FROM #t1 t1
It doesn't answer the question, but it solves your problem.
Use TRY_PARSE (SQL Server 2012+):
SELECT ISNULL(TRY_PARSE(column_name AS INT),0)
FROM your_table;
LiveDemo

Referring to column values directly without using variables in T-SQL

Is there a way in T-SQL (SQL Server 2005) to assign a whole record to a record variable and then refer to the particular values using column names?
I mean, instead of:
select #var1 = col1,
#var2 = col2
from mytable
where ID = 1;
and referring to them as #var1 and #var2, something like
#record =
select col1, col2
from mytable
where ID = 1;
and referring to them like #record.col1 and #record.col2 .
I am beginner in t-sql, so hopefully the question is not too trivial.
You can create a table variable and select the whole resultset into it:
DECLARE #tt TABLE (col1 INT, col2 INT)
INSERT
INTO #tt
SELECT col1, col2
FROM mytable
WHERE id = 1
, but you cannot access its data except than in the SELECT query as well.
With pure TSQL (that it without custom datatypes) the thing you ask is impossible.
sounds like you are a programmer ... look at linq maybe as it does what you want.
You can use a temporary table and SELECT...INTO to avoid specifying the column names at the beginning :
SELECT Field1, Field2
INTO #TempTable
FROM MyTable
WHERE MyTable.MyID = 1
but of course you'll still need the FROM #TempTable part when referring to the column names.
SELECT Field1, Field2
FROM #TempTable
and of course to remember to drop the table at the end :
DROP #TempTable
The app code is where you'd normally refer to a single row at a time as a variable.
You could use XML, but you'd have to play with this...
DECLARE #MyRecord xml
DECLARE #Mytable TABLE (col1 int NOT NULL, col2 varchar(30) NOT NULL)
INSERT #Mytable (col1, col2) VALUES (1, 'bob')
select #MyRecord =
(SELECT *
from #Mytable
where col1 = 1
FOR XML AUTO)
SELECT #myRecord.value('./#col', 'int') --also #myRecord.value('#col', 'int')
--gives error
Msg 2390, Level 16, State 1, Line 12
XQuery [value()]: Top-level attribute nodes are not supported
Buried in the Transact SQL documentation I came across this restriction on variables:
Variables can be used only in expressions, not in place of object names or keywords.
Since you'd need to use an object name to qualify a column I don't believe that this is allowed.