Union leads to error converting varchar to numeric - sql

I'm reposting my question from yesterday with the addition of code.
I'm creating a new table LAB_RESULT as a union of two tables (Labs and CTE). A column called result_num (numeric (18,5)) is causing problems in LAB_RESULT.
Table LAB_RESULT is declared first with explicit data types.
CREATE TABLE dbo.LAB_RESULT
(
[LAB_RESULT_CM_ID] VARCHAR (36),
[RESULT_NUM] NUMERIC (18,5)
)
INSERT INTO [dbo].[LAB_RESULT] (LAB_RESULT_CM_ID, RESULT_NUM)
SELECT LAB_RESULT_CM_ID, RESULT_NUM
FROM [etl].[lab_result]
LAB_RESULT draws from varchar columns in tables LABS and CTE. I have used try_cast in both A and B to make sure nothing slips through.
So when I select from (LABS U CTE), I get:
Msg 8114
Error converting data type varchar to numeric
but when I select from only LABS or only CTE (all there just commented out) the data loads fine.
This is happening even if I use cast(null as numeric).
SELECT LAB_RESULT_CM_ID, RESULT_NUM
FROM
((SELECT
NEWID() AS LAB_RESULT_CM_ID,
CAST(NULL AS NUMERIC(18, 5)) AS RESULT_NUM
FROM [dbo].[Labs] as labs
UNION
(SELECT
NEWID() as LAB_RESULT_CM_ID,
CAST(NULL as NUMERIC(18, 5)) AS RESULT_NUM
FROM CTE)
What gives? I would really appreciate some insight. TIA!

Related

Error casting varchar to decimal even though SQL query doesn't return any results

I have a SQL query which fetches no rows. I am using cast function in select statement to cast from varchar to decimal, I am getting exception saying couldn't cast varchar to decimal.
This is my query
select distinct
order_id, order_amt,
cast(replace(order_amt, ',', '') as decimal(11, 2)) as amt
from
table1
left join
table2 on table1.order_id = table2.order_num
where
table2.order_num is null
and table1.order_id not in (123, 456)
Not sure why I am getting error, even though query returns no results.
Any inputs are highly appreciated.
You don't have control over where SQL Server decides to evaluate expressions. So, expressions might be evaluated (and generate an error), even on rows that are filtered out.
In this case, there is a very simply solution: try_cast():
Try_Cast(Replace(order_amt, ',', '') as decimal(11,2)) as amt

How to convert multiple varchar values into smallint

Pardon me, I was trying hard to find the answer, but most of the questions are related in the forum related to converting one value, not the whole set.
I am trying to pass the subquery values to the main query but the subquery returning varchar and the main query column is accepting smallint. I tried cast and convert but didn't help me.
select time_off_type_no
from schedtime
where activity_no in (select AT_NUMBERS from ACTIVITY where AT_ID = 105)
This query is throwing the following exception
Conversion failed when converting the varchar value '483,484,485,486,487,488,489' to data type smallint
Any advice on how to convert the values much appreciated.
Following query returning '483,484,485,486,487,488,489' and I want to convert all the values to SmallInt or int to pass it to the main query.
select AT_NUMBERS
from ACTIVITY
where AT_ID = 105
Please try nested casting like:
SELECT CAST(CAST(AT_NUMBERS AS DECIMAL) AS SMALLINT) from ACTIVITY where AT_ID=105
EDIT: Since the returned value is a comma-delimited string, I think this would help if the version of SQL Server is at least 2016
;with cte (ID) as (
Select string_split (AT_NUMBERS,',') as ID
from ACTIVITY
where AT_ID=105
)
select time_off_type_no from schedtime where activity_no in (
SELECT CAST(CAST(ID AS DECIMAL) AS SMALLINT) from cte
)
If SQL SERVER version is below 2016, we'll need to develop our own split function. You can find examples in How to split a comma-separated value to columns
Try this as an example if so, working in Sql Server 2008:
DECLARE #t TABLE
(
EmployeeID INT,
Certs VARCHAR(8000)
)
INSERT #t VALUES (1,'B.E.,MCA, MCDBA, PGDCA'), (2,'M.Com.,B.Sc.'), (3,'M.Sc.,M.Tech.')
SELECT EmployeeID,
LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS Certs
FROM
(
SELECT EmployeeID,CAST('<XMLRoot><RowData>' + REPLACE(Certs,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
FROM #t
)t
CROSS APPLY x.nodes('/XMLRoot/RowData')m(n)
Ref: https://blog.sqlauthority.com/2015/04/21/sql-server-split-comma-separated-list-without-using-a-function/
I think you need to split the string by comma if these (483,484,485,486,487,488,489) are individual numbers. If this is whole integer value, not even Big Int limit is like this.
See MS documentation:
https://learn.microsoft.com/en-us/sql/t-sql/data-types/int-bigint-smallint-and-tinyint-transact-sql?view=sql-server-2017
If your SQL server version is more than 2016 or more, then you can use string_split function in this way.
--Use try_cast or Try_convert to avoid any conversion error as well.
select Try_cast(value as int) Integervalue from string_split ('483,484,485,486,487,488,489',',')
Output:
Integervalue
483
484
485
486
487
488
489
--this will work if it is pure integer value, else it needs to be converted to decimal.
Please make sure to use cross apply if you are using against tables.
If it is less than 2016, you might have to build one string split function as mentioned here.
Splitting the string in sql server

Calculating SQL Average with non-numeric data in Table

I have this SQL query that is failing on this nvarchar, even though it seems to me that it is properly guarded for a cast to work. I am trying to get the average of the values for correctly formatted numerical values on a database that I only have read access to.
select TagName, count(TagName) as Freq,
sum(isnumeric(value)) as GoodNums,
avg(case isnumeric(value) when 1 then cast(value as numeric) else 0 end) as "Avg",
Min(Timestamp) as StartTime,
Max(Timestamp) as EndTime
from HH_Data_9 group by TagName
However I never really completely grokked the SQL syntax for combinations of CASE, aggregate functions, and GROUP_BY, so maybe I am just writing it wrong (Tried quite a few things before posting this). Note that the "GoodNums" column works and is giving reasonable answers but when I add the "Avg" column to the query the whole thing errors out of with:
Msg 8114, Level 16, State 5, Line 1
Error converting data type nvarchar to numeric.
This is Microsoft SQL Server 2014 by the way. Any ideas?
Just want to caution that this approach is very dangerous. Consider the following table structure:
CREATE TABLE TestTable
(
FieldType NVARCHAR(50) ,
FieldValue NVARCHAR(50)
)
GO
INSERT INTO dbo.TestTable
VALUES ( 'INT', '5' ),
( 'INT', '15' ),
( 'MONEY', '5.5' )
SELECT *
FROM dbo.TestTable
WHERE FieldType = 'INT'
AND CAST(FieldValue AS INT) > 10
On my machine this query works, but the thing here is that many assumes that this predicate will evaluate from left to right. But this is incorrect. SQL Server engine may decide to evaluate this expression from right to left. And in this case you will get Conversion failed error. It's called ALL-AT-ONCE principle. However in your example this is not applicable, but just wanted to mention.

How to convert varchar column values into int?

I have a column toysid which is of varchar datatype in one table. Also another table having same the column toysid with int datatype (I know I can modify column for first table but I have to follow some procedure to keep it as varchar).
I have written following query to join the table:
select study.toysid
from study
join concepts on study.toysid = concepts.toysid
The query returns error:
Conversion failed wher converting varchar datatype into int
Hence I have tried below query:
select study.toysid
from study
join concepts on convert(int, study.toysid) = concepts.toysid
I got the same error. How to convert it? I have searched in many websites but I'm unable to get solution. Please anyone help on this.
Make sure you dont have anything other than numbers in your toysid column. I suspect there are characters other than numbers in that column. once you are sure, try the below query..
select study.toysid
from study join concepts
on cast(study.toysid as int) = concepts.toysid
or
select study.toysid
from study join concepts
on cast(study.toysid as varchar(100)) = cast(concepts.toysid as varchar(100))
You can omit such records which having non-numeric value and then cast with integer like below:
select Mystudy.toysid
from concepts
join (Select study.toysid From study WHERe ISNUMERIC(study.toysid)= 1) As MyStudy
on convert(int, MyStudy.toysid) = concepts.toysid

Understanding SQL Server behaviour with min(datetime)

(long story short, was just a dumb assumption by me, I was sure a column was a datetime and it wasn't - so don't expect to find anything interesting in this question, leaving it here so that dems gets his rightfully accepted answer)
I wrote a simple query like this:
SELECT ID, MIN(DateMadeActive) AS DateMadeActive
FROM RecordStateField WHERE RecordStatusID in (2, 3)
GROUP BY ID
Where DateMadeActive is a datetime column. This returned what I expected:
ID DateMadeActive
1 20/06/2011 16:15:04
2 20/06/2011 16:14:28
Now I inserted this into a new table, but inserting the result of MIN(DateMadeActive) into a datetime column of another table gave me this error:
Msg 8115, Level 16, State 2, Line 1
Arithmetic overflow error converting expression to data type datetime.
So to test this I change my select to this:
SELECT ID, CAST(Min(DateMadeActive) as datetime) AS DateMadeActive
FROM RecordStateField WHERE RecordStatusID in (2, 3)
GROUP BY ID
Same exception. I can write it like this and make it work:
SELECT ID, CONVERT(datetime, Min(DateMadeActive), 103) AS DateMadeActive
FROM RecordStateField WHERE RecordStatusID in (2, 3)
GROUP BY ID
So I can get it working, but this confuses me. The documentation for MIN(expression) says the return type should be the same as expression, but what seems to be happening is that MIN(datetime) is returning nvarchar(255). I can confirm this by running this:
SELECT ID, Min(DateMadeActive) AS DateMadeActive
INTO TestTable
FROM RecordStateField WHERE RecordStatusID in (2, 3)
GROUP BY ID
And I can see that the DateMadeActive column is of type nvarchar(255). Anyone shed any light on this? Just a documentation bug in MSDN?
It looks to me that DateMadeActive in [RecordStateField] is a VARCHAR(255) field. Could you post the table definitions?
I ask this because MIN() has neve rchanged the type for me before. And so if the result is a VARCHAR(255) it seems the input must also be a VARCHAR(255)