I am trying to inner join a smallint field on a varchar field. I only need the integer values but I am getting an error. The varchar field has integers and strings. I do not need the ID field only the DESC.
I get an error:
Conversion failed when converting the varchar value 'AWOL' to data type smallint.
This is what the table look like:
==================================
|ID |DESC |
|==========|=====================|
|ACAMPROCAL|acamprosate calcium |
|----------|---------------------|
|BUPROPION |bupropion |
|----------|---------------------|
|1 |Other |
|----------|---------------------|
|4 |Expired |
|----------|---------------------|
|3 |Dschg |
|----------|---------------------|
|AWOL |Absence without Leave|
==================================
Here is the query I've tried but also commented out:
SELECT
CASE_NUM, LAST_NAME, FIRST_NAME, MI, '' AS NA,
DOB, SEX, [ADDRESS], '' AS NA, CITY, STATE, ZIP
--,CONVERT(SMALLINT, CONVERT(VARCHAR(55), CDTBL1.[DESC]))
--,CASE WHEN CDTBL1.ID BETWEEN 1 AND 99999 THEN CDTBL1.[DESC]
--END AS COUNTY
FROM
CDCLIENT
INNER JOIN
CDTBL1 ON CDCLIENT.ADDR_COUNTY_ID = CDTBL1.ID
Change
'ON CDCLIENT.ADDR_COUNTY_ID = '
to
'ON CAST(CDCLIENT.ADDR_COUNTY_ID as varchar) = '
You should check the datatypes of the columns you are joining on to be sure that they are the same type.
Generally I would think an ID column would be some type of int, but the table you provided above contains varchar values in the ID column as well.
There is a precedence to the datatypes in SQL and smallint is above varchar. There is an implicit conversion taking place that is causing the failure.
More info here: https://msdn.microsoft.com/en-us/library/ms190309.aspx
This is an issue with Implicit Conversions and SQL Server chose the wrong data to convert. Typically, when you need to compare different data types, it's usually best to explicitly convert one to another.
Microsoft has a nice table on what data types are allowed to implicitly and explicitly convert between.
If you want non-negative integers, then use logic like this:
select (case when CDTBL1.[DESC] not like '%[^0-9]%'
then convert(smallint, CDTBL1.[DESC])
end)
Note that you might also want to check the length and values of the field, to be sure you don't get an error.
In SQL Server 2012+, you can simplify this using try_convert():
select try_convert(smallint, CDTBL1.[DESC])
This returns NULL if an error would occur. But, it is not available in SQL Server 2008.
Related
I am trying to import legacy data from another system into our system. The problem I am having is that the legacy data is dirty- very dirty! We have a field which should be an integer, but sometimes is a varchar, and the field is defined as a varchar...
In SQL Server, how can I do a select to show those records where the data is varchar instead if int?
Thanks
If you want to find rows1 where a column contains any non-digit characters or is longer than 9 characters (either condition means that we cannot assume it would fit in an int, use something like:
SELECT * FROM Table WHERE LEN(ColumnName) > 9 or ColumnName LIKE '%[^0-9]%'
Not that there's a negative in the LIKE condition - we're trying to find a string that contains at least one non-digit character.
A more modern approach would be to use TRY_CAST or TRY_CONVERT. But note that a failed conversion returns NULL and NULL is perfectly valid for an int!
SELECT * FROM Table WHERE ColumnName is not null and try_cast(ColumnName as int) is null
ISNUMERIC isn't appropriate. It answers a question nobody has ever wanted to ask (IMO) - "Can this string be converted to any of the numeric data types (I don't care which ones and I don't want you to tell me which ones either)?"
ISNUMERIC('$,,,,,,,.') is 1. That should tell you all you need to know about this function.
1If you just want a count, as per the title of the question, then substitute COUNT(*) for *.
In SQL Server, how can I do a select to show those records where the data is varchar instead of int?
I would do it like
CREATE TABLE T
(
Data VARCHAR(50)
);
INSERT INTO T VALUES
('102'),
(NULL),
('11Blah'),
('5'),
('Unknown'),
('1ThinkPad123'),
('-11');
SELECT Data -- Per the title COUNT(Data)
FROM
(
SELECT Data,
cast('' as xml).value('sql:column("Data") cast as xs:int ?','int') Result
FROM T --You can add WHERE Data IS NOT NULL to exclude NULLs
) TT
WHERE Result IS NULL;
Returns:
+----+--------------+
| | Data |
+----+--------------+
| 1 | NULL |
| 2 | 11Blah |
| 3 | Unknown |
| 4 | 1ThinkPad123 |
+----+--------------+
That if you can't use TRY_CAST() function, if you are working on 2012+ version, I'll recommend that you use TRY_CAST() function like
SELECT Data
FROM T
WHERE Data IS NOT NULL
AND
TRY_CAST(Data AS INT) IS NULL;
Demo
Finally, I would say do not use ISNUMERIC() function because of (from docs) ...
Note
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).
I have a table which contains both text and numbers in a varchar column called EMPLOYEE_CODE. I want to ignore all the text and get the Highest number in the Column and then + 1 which i can then assign to a new employee. The code below would work on an INT Column but not on the VARCHAR because of the text i get the below error:
Conversion failed when converting the varchar value 'testusercode' to
data type int.
SELECT MAX(EMPLOYEE_CODE) + 1 as Target
FROM [COMPANY].[dbo].[USER]
WHERE EMPLOYEE_CODE + 1 NOT IN (SELECT EMPLOYEE_CODE From dbo.USER)
I am guessing I have to add convert or cast to the query but not sure how
You can use ISNUMERIC to check for number, get maximum value and add 1.
SELECT MAX(EMPLOYEE_CODE) + 1 as Target
FROM [COMPANY].[dbo].[USER]
WHERE ISNUMERIC(EMPLOYEE_CODE) = 1
If you are using newer versions of SQL Server, you can also use
SELECT MAX(EMPLOYEE_CODE) + 1 as Target
FROM [COMPANY].[dbo].[USER] WHERE TRY_PARSE(EMPLOYEE_CODE AS int) IS NOT NULL
There are TRY_CAST and TRY_CONVERT also for same stuff. You can easily check which one suits your purpose.
https://learn.microsoft.com/en-us/sql/t-sql/functions/try-cast-transact-sql
Let me first point out that my question is going to be very very close to this question: map-column-data-to-a-value-oracle
Please quickly read that one first.
Now in my case I need the exact same thing but not as the primary query. Instead I need the information as one part of my query.
I have this table:
someId | someValue | dataType
1 | 500 | 1
2 | someValue | 2
And I know that dataType "1" means "Integer". I also know the meaning of the other values in the dataType column.
So I want to select all entries in the table but have their dataTypes as their human readable values instead of their numbers:
Results:
1, 500, Integer
2, someString, String
Trying to apply the solution of the question I linked, I created a subquery like
SELECT
someId,
someValue,
(
SELECT CASE
WHEN dataType = 1 THEN 'INTEGER'
WHEN dataType = 2 THEN 'FLOAT'
WHEN dataType = 3 THEN 'TEXT'
ELSE 'DATE'
END
myTable
) as myDataType
I will get a subquery that returns more than 1 result and Oracle will complain.
Since I access the DB through SQL directly, I need a "pure SQL" solution. Otherwise I could just parse the value through a mapping, in say PHP. But that's not possible here. I am shooting some queries at a DB to try and gather information about the data and structure, which we don't know about. So only SQL is available.
Get rid of the subquery:
SELECT someId,
someValue,
CASE
WHEN dataType = 1 THEN 'INTEGER'
WHEN dataType = 2 THEN 'FLOAT'
WHEN dataType = 3 THEN 'TEXT'
ELSE 'DATE'
END as Datatype
from myTable
I am trying to take an average of a column in my database. The column is AMOUNT and it is stored as NVARCHAR(300),null.
When I try to convert it to a numeric value I get the following error:
Msg 8114, Level 16, State 5, Line 1
Error converting datatype NVARCHAR to NUMBER
Here is what I have right now.
SELECT AVG(CAST(Reimbursement AS DECIMAL(18,2)) AS Amount
FROM Database
WHERE ISNUMERIC(Reimbursement) = 1
AND Reimbursement IS NOT NULL
You would think that your code would work. However, SQL Server does not guarantee that the WHERE clause filters the database before the conversion for the SELECT takes place. In my opinion this is a bug. In Microsoft's opinion, this is an optimization feature.
Hence, your WHERE is not guaranteed to work. Even using a CTE doesn't fix the problem.
The best solution is TRY_CONVERT() available in SQL Server 2012+:
SELECT AVG(TRY_CONVERT(DECIMAL(18,2), Reimbursement)) AS Amount
FROM Database
WHERE ISNUMERIC(Reimbursement) = 1 AND Reimbursement IS NOT NULL;
In earlier versions, you can use CASE. The CASE does guarantee the sequential ordering of the clauses, so:
SELECT AVG(CASE WHEN ISNUMERIC(Reimbursement) = 1 AND Reimbursement IS NOT NULL
THEN CONVERT(DECIMAL(18,2), Reimbursement))
END)
FROM Database;
Because AVG() ignores NULL values, the WHERE is not necessary, but you can include it if you like.
Finally, you could simplify your code by using a computed column:
alter database add Reimbursement_Value as
(CASE WHEN ISNUMERIC(Reimbursement) = 1 AND Reimbursement IS NOT NULL
THEN CONVERT(DECIMAL(18,2), Reimbursement))
END);
Then you could write the code as:
select avg(Reimbursement_Value)
from database
where Reimbursement_Value is not null;
Quote from MSDN...
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
select isnumeric('+')---1
select isnumeric('$')---1
so try to add to avoid non numeric numbers messing with your ouput..
WHERE Reimbursement NOT LIKE '%[^0-9]%'
If you are on SQLServer 2012,you could try using TRY_Convert which outputs null for conversion failures..
SELECT AVG(try_convert( DECIMAL(18,2),Reimbursement))
from
table
I am guessing that since it is Nvarchar you are going to find some values in there with a '$','.', or a (,). I would run a query likt this:
SELECT Amount
FROM database
WHERE Amount LIKE '%$%' OR
Amount LIKE '%.%' OR
Amount LIKE '%,%'
See what you get and my guess you will get some rows returned and then update those rows and try it again.
Currently your query would pull all numbers that are not all numeric which is a reason why it is failing too. Instead try running this:
SELECT AVG(CAST(Reimbursement AS DECIMAL(18,2)) AS Amount
FROM Database
--Changed ISNUMERIC() = to 0 for true so it will only pull numeric numbers.
WHERE ISNUMERIC(Reimbursement) = 0 and Reimbursement IS NOT NULL
I have a table with a field named MINIMUM_AGE. The values stored in this field are of type nvarchar:
17 years
54 years
N/A
65 years
I would like to apply a WHERE clause on the column to check for a certain age range. To do that I need to parse out the age from the field values.
So, I think I need to select the first two characters, then cast them into an integer. Also, some fields may not contain numbers for the first two characters. Some may simply be N/A. So, I will need to check for that before casting.
Can someone explain how to accomplish this?
Here is the SQL Fiddle that demonstrates the below query:
SELECT CASE
WHEN MINIMUM_AGE <> 'N/A'
THEN CAST(LEFT(MINIMUM_AGE, 2) AS int)
ELSE 0
END
FROM MyTable
Note: the CASE expression can only return one data type. So, in the example above if the MINIMUM_AGE is N/A then it returns 0.
If you would rather have it return null, then use the following:
SELECT CASE
WHEN MINIMUM_AGE <> 'N/A'
THEN CAST(LEFT(MINIMUM_AGE, 2) AS int)
END
FROM MyTable