SQL: How use case and cast in a query? - sql

I want to cast VARCHAR to INT, but in my table i have some value like '???' then SQL Server launch this expcetion :
Conversion failed when converting the varchar value '????' to data type int.
Severity 16
I could convert this '???' to NULL, that's no problem, but how do that ?
I'm trying to do something like this:
INSERT INTO labbd11..movie(title, year)
SELECT movies.title,
CASE movies.mvyear IS '????' THEN NULL ELSE CAST (movies.mvyear AS INT)
FROM disciplinabd..movies
But nothing works ..
Any ideas guys ?

You might just want to solve this in general and deal with any non-int value the same way
INSERT INTO labbd11..movie(title, year)
SELECT movies.title,
CASE WHEN IsNumeric(movies.mvyear+ '.0e0') <> 1 THEN NULL
ELSE CAST (movies.mvyear AS INT) END
FROM disciplinabd..movies
See this question

I believe you would want something like
INSERT INTO labbd11..movie(title, year)
SELECT movies.title,
CAST( CASE movies.mvyear
WHEN '????' THEN NULL
ELSE movies.mvyear
END AS INT)
FROM disciplinabd..movies
You want your CASE statement to return a VARCHAR (either the MVYEAR or NULL) and then you want the CAST to operate on the result of the CASE.

INSERT INTO labbd11..movie(title, year)
SELECT movies.title,
CASE WHEN movies.mvyear = '????' THEN NULL
ELSE CAST (movies.mvyear AS INT) END
FROM disciplinabd..movies

INSERT INTO labbd11..movie(title, year)
SELECT
movies.title,
CAST(CASE WHEN movies.mvyear = '????' THEN NULL ELSE movies.mvyear END AS INT)
FROM
disciplinabd..movies

You can also use:
CAST(NULLIF(movies.mvyear,'????') AS INT)

Related

Conversion failed when converting the varchar value 'U' to data type int

I'm getting an "error converting varchar to int" for fields Q1_c and Q2_c.
Those fields are CHAR(1) and the values for those fields are either 1,2,3,4,5, or U, but it will not convert when there is a U, so I am trying to change the value of U to something else like 0. I have also tried CAST(a.q2_c as varchar(1)) = 'U' - but that doesn't work either. Should I be using INT or VARCHAR()? I have also tried using CONVERT instead of CAST.
ALTER VIEW [dbo].[vCDCP_rptInfantImprove]
as
select distinct
IND.tb_cdcp_individuals as Individuals_IndividualID
, A.[tb_cdcp_individuals] as ATQInfant_IndividualID
, A.CreateDate as ATQInfant_CreateDate
, CAST(a.q1_c as varchar(3)) as A_Q1
, CAST(a.q2_c as varchar(3)) as A_Q2
---Infant Sum
, Sum(isnull(cast(a.Q1_c as int),0)) + Sum(isnull(cast(a.Q2_c as int),0)) as InfantSum
---Change U to 0
, case when CAST(a.q1_c as int) = 'U' then 0 else 0 end as Unknown1
, case when CAST(a.q2_c as int) = 'U' then 0 else 0 end as Unknown2
from DBO.tb_cdcp_ATQInfant a
left join DBO.tb_cdcp_individuals ind on a.[tb_cdcp_individuals] = ind.[tb_cdcp_individuals]
where ind.agegroup_c = 'C'
group by IND.tb_cdcp_individuals, A.tb_cdcp_individuals, A.CreateDate
, a.q1_c
, a.q2_c
GO
You can go about this in a couple of different ways:
Since the fields are in character format, replace 'u' with '0' and then convert it into int:
CAST(Replace(q1_c,'u','0') as int)
Or if you wanted to create a new calculated field you can directly create an integer field:
Case when q1_c='u' then 0 else CAST(q1_c as int) end as q1_c_calc
Hope this helps.
A simple idea that occurs to me is to define another table ... with a CHAR(1) for every possible value, and an INT for the corresponding number. Then, simply JOIN to that table. No doubt the SQL engine will simply slurp the whole thing into memory if it only contains 5 rows. If someday more values need to be encoded, it's easy to do this.
Assuming that you cannot do anything else to clean the data that is stored in the tables or do anything to control the values being inserted in said tables you can use TRY_CONVERT or TRY_CAST. Both functions when return NULL if the CHAR(1) cannot convert to an INT. You just test for NULL that way you don't have to worry about any other rouge characters that may get accidentally inserted.
IF OBJECT_ID('tempdb..#sample') IS NOT NULL
BEGIN
DROP TABLE #sample
END
GO
CREATE TABLE #sample
(
q1_c CHAR(1),
q2_c CHAR(1)
)
INSERT INTO #sample(q1_c , q2_c )
VALUES ('1','1'),('2','2'),('3','3'),('4','4'),('5','5')
,('u','U'),('$','$'), ('#','#'), ('^','^'), ('&','&'), ('*','*'),
('1','1'),('2','2'),('3','3'),('4','4'),('5','5')
SELECT CASE WHEN TRY_CAST(q1_c AS INT) IS NULL THEN '0' ELSE q1_c END A_Q1,
CASE WHEN TRY_CONVERT(INT, q2_c) IS NULL THEN '0' ELSE q2_c END A_Q2,
SUM(TRY_CAST(q1_c AS INT)) sumQ1_c, SUM(TRY_CONVERT(INT, q2_c)) sumQ2_c
FROM #sample
GROUP BY q1_c, q2_c
You have multiple reasons for this not to work:
First of all, you have to make sure the values that you are trying to cast are compatible with the type you are trying to cast into. CAST(a.q1_c as int) will work fine when the value is 1,2,3,4,5, but will fail when the value is 'U'. If you're sure that the values are 1,2,3,4,5, or U, you could use 'case'
CAST(case when a.q1_c = 'U' then 0 else a.q1_c end as int) = 'U'
if not, ISNUMERIC() might work for this case.
Also CAST(a.q1_c as int) = 'U' what are you tryng to do here? Why not just a.q1_c = 'U' ?
Please try this:
ALTER VIEW [dbo].[vCDCP_rptInfantImprove]
as
select distinct
IND.tb_cdcp_individuals as Individuals_IndividualID
, A.[tb_cdcp_individuals] as ATQInfant_IndividualID
, A.CreateDate as ATQInfant_CreateDate
, CAST(a.q1_c as varchar(3)) as A_Q1
, CAST(a.q2_c as varchar(3)) as A_Q2
---Infant Sum
, Sum(isnull( case when a.Q1_c = 'U' then 0 else cast(a.Q1_c as int) end, 0 )) + Sum(isnull( case when a.Q2_c = 'U' then 0 else cast(a.Q2_c as int) end, 0 )) as InfantSum
--- Remove cast here and not sure what goes in else part.
, case when a.q1_c = 'U' then 0 else a.q1_c end as Unknown1
, case when a.q2_c = 'U' then 0 else a.q2_c end as Unknown2
from DBO.tb_cdcp_ATQInfant a
left join DBO.tb_cdcp_individuals ind on a.[tb_cdcp_individuals] = ind.[tb_cdcp_individuals]
where ind.agegroup_c = 'C'
group by IND.tb_cdcp_individuals, A.tb_cdcp_individuals, A.CreateDate
, a.q1_c
, a.q2_c
GO

Converting varchar to int (a strange case?)

I have scoured through all "Varchar to Int" posts but can't seem to find anyone with this issue (although, I am fairly new to SQL so I may be doing something fundamentally wrong):
SELECT *
FROM [TABLE]
WHERE CONVERT(INT,
CASE
WHEN NOT CONVERT(VARCHAR(12), dept_code) LIKE '%[^0-9]%' THEN 8900
END) < 9000;
It's a fairly simple query, where the goal is to filter out all the values in field "dept_code" so that only fully numeric values less than 9000 are kept; varchars and non-numeric values are fine to stay. When running the above I still get the error "Conversion failed when converting the varchar value 'E103' to data type int."
Any help would be appreciated.
You can simply this query by avoiding CASE and Regex like expression. You can use IsNumeric function to filter numeric rows and then apply the condition by converting dept_code of filtered rows to int, like below -
select * from tablex
where ISNUMERIC(dept_code) = 0 --alphanumeric code
OR(ISNUMERIC(dept_code) = 1 and Convert(int, dept_code) < 9000) -- numeric less than 9000
Example here
Use try_convert() or try_cast():
SELECT t.*
FROM [TABLE] t
WHERE TRY_CONVERT(int, dept_code) < 9000
If you want to speed this query, you can materialize a computed column and add an index:
alter table [table] add dept_code_int as (try_convert(int, dept_code)) persisted;
create index idx_table_dept_code_int on [table](dept_code_int);
You are missing an else in your case statement ... Secondly do your numeric dept_codes get to be really big ... this thing will choke on that.
SELECT *
FROM [TABLE]
WHERE CONVERT(INT,
CASE
WHEN NOT CONVERT(VARCHAR(12), dept_code) LIKE '%[^0-9]%' THEN 8900 ELSE dept_code
END) < 9000;
Try this: http://sqlfiddle.com/#!18/bb6b7/17
;WITH TABLE_ENHANCED AS
(
SELECT
t.*
, dept_code_numeric =
CASE
WHEN CONVERT(VARCHAR(12), dept_code) NOT LIKE '%[^0-9]%'
THEN CONVERT(INT, dept_code)
ELSE 0
END
FROM [TABLE] t
)
SELECT
*
FROM TABLE_ENHANCED
WHERE dept_code_numeric < 9000
Try below Script
SELECT *
FROM [TABLE]
WHERE isnumeric(dept_code)=1
and dept_code<9000;
This should work. The conversion to int is implicit.
SELECT *
FROM test
WHERE (ISNUMERIC(dept_code)=1 and dept_code<9000)
or (ISNUMERIC(dept_code) = 0)

How to sort a column in ascending order where the column contains varchar and numeric, using SQL?

Actually my column is in varchar, and it has numeric and varchar type data, i just wanted to sort numeric first then varchar type.
I refered and got this:
SELECT
...
ORDER BY
CASE
WHEN ISNUMERIC(value) = 1 THEN CONVERT(INT, value)
ELSE 9999999 -- or something huge
END,
value
It works, but why we need to use ELSE 9999999 here, instead what we can replace...?
Any solution for this...!
You could use:
SELECT *
FROM tab
ORDER BY IIF(TRY_CAST(val AS INT) IS NULL, 1, 0),TRY_CAST(val AS INT);
DBFiddle Demo
You can try this as an alternative solution.
SELECT
...
ORDER BY
ISNUMERIC(value) DESC
, CASE
WHEN ISNUMERIC(value) = 1 THEN CONVERT(INT, value)
END
,value

converting varchar to Int SQL SERVER

I needed help with something I am not entirely sure how to resolve.
This is my code :
SELECT DISTINCT
Nr_of_Times_Cust_No_Appears=CASE WHEN CAST(a.TV_Code AS Int)-CAST(BB_Code AS Int)=0 THEN COUNT(*) OVER (PARTITION BY BB_Code) ELSE 'Not same' END
FROM table
Basically, the above code is meant to make sure that the substraction of TV Code and BB Code is Zero(0) if not then 'Not Same'. TV Code and BB Code are both varchar that are CAST to Int. The problem lies in the ELSE ' NOT SAME'.
This is the output I get from SQL SERVER Management Studio:
Conversion failed when converting the varchar value 'Not same' to data type int.
What should I do to make it work?
UPDATE: I finally found the workaround.
CAST(COUNT(*) OVER (PARTITION BY XX) AS Varchar)..... It worked!!!!
This is happening because the output of your CASE statement is returning count() (an integer) from THEN 'Not same' (a string) from the ELSE. They need to be the same types. If you cast your count() to a string you will be fine.
SELECT DISTINCT Nr_of_Times_Cust_No_Appears=
CASE WHEN CAST(a.TV_Code AS Int)-CAST(BB_Code AS Int)=0
THEN CAST(COUNT(*) OVER (PARTITION BY BB_Code) AS VARCHAR)
ELSE 'Not same'
END
FROM table
Alternative:
SELECT DISTINCT Nr_of_Times_Cust_No_Appears=
CASE WHEN CAST(a.TV_Code AS Int)-CAST(BB_Code AS Int)=0
THEN COUNT(*) OVER (PARTITION BY BB_Code)
ELSE -1
END
FROM table
In the consuming code i.e. User Interface, if Nr_of_Times_Cust_No_Appears < 0 then show 'Not same'!
The error is simply occurring as your destination column can only have one data type.
The first part of your CASE statement is effictively setting the column type to expect an integer, so when you hit the ELSE section and try to insert Not Same, you're getting the error.
Sample:
SELECT Num
INTO #T
FROM ( SELECT '1' AS Num
UNION
SELECT '2'
) AS val
SELECT CASE WHEN Num = '1' THEN CAST(Num AS INT)
ELSE 'Not 1'
END AS OutputVal
FROM #T
DROP TABLE #T
Gives you:
Conversion failed when converting the varchar value 'Not 1' to data type int.
So you need to insert an acceptable value, which could be NULL:
Sample:
SELECT Num
INTO #T
FROM ( SELECT '1' AS Num
UNION
SELECT '2'
) AS val
SELECT CASE WHEN Num = '1' THEN CAST(Num AS INT)
ELSE NULL
END AS OutputVal
FROM #T
DROP TABLE #T
Check variable Nr_of_Times_Cust_No_Appears. It seems to be int, but you try to set it 'Not same'.

SQL Server AVG function to return NULL if all values are NULL

I have a table similar to this
+--+-----+----+
|ID|Entry|Exit|
+--+-----+----+
|18|32154|NULL|
+--+-----+----+
|19|NULL |NULL|
+--+-----+----+
When I select AVG(Entry) it correctly gives me 32154, when I select AVG(Exit) it blows up saying "Operand data type void type is invalid for avg operator."
How can I get NULL as the average for a column that only has NULL values?
Thanks,
Try using CASE like this
SELECT CASE WHEN SUM(Exit) IS NULL THEN NULL ELSE AVG(Exit) END AS MyAverage
FROM MyTable
I think The problem is with the column name. Just change the column name to ExitCol and check.
In that case even SELECT AVG(ExitCol) AS MyAverage FROM MyTable also will work
The problem is that the Exit column doesn't have a data type that is compatible with the SUM function.
You can run this query to see that you indeed get NULL from SUM if all values are NULL (and a proper data type)
select sum(a) from (select convert(int, null) a union select null) a
Select avg(isnull(Exit,0)) from table
use set xact_abort off to get it to return null
declare #a table (id int, amount numeric(10,2))
insert into #a values (1, null), (2,null), (3,null)
set xact_abort off
select AVG(amount)
from #a