SQL comma separated value in IN clause case statement error - sql

I'm encountering an error on the item below and I don't understand why. Can anyone shed some light on it for me?
CREATE FUNCTION dbo.fn_AcMonthOrder
(
#Month varchar(100)
)
RETURNS INT
AS
BEGIN
DECLARE #MonthOrder Int
SET #MonthOrder =
(CASE
WHEN #Month IN ('Aug','August',8) THEN 1
WHEN #Month IN ('Sep','September',9) THEN 2
WHEN#Month IN ('Oct','October',10) THEN 3
...
ELSE 0 END)
RETURN #MonthOrder
END
If I attempt to call this function then it works fine for an integer, but not for the varchars. I.e. PRINT #dbo.fn_AcMonthOrder(8) will return 1 as expected, but PRINT #dbo.fn_AcMonthOrder('Aug') Or PRINT #dbo.fn_AcMonthOrder('August') returns the following error:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the varchar value 'Aug' to data type int.

When you use different data types in an expression, SQL Server follows data type precedence. In this case:
8 IN ('Aug','August', 8)
You're mixing int with varchar. Since int has higher precedence, it will convert the varchar to int. The reason this particular case does not throw an error might be optimization. This does throw an error:
8 IN ('Aug','August',10)
And this does not throw an error:
'Aug' IN ('Aug','August',8)
But this throws an error again:
'Sept' IN ('Aug','August',8)
This confirms that the optimizer first compares the elements that do not require conversion. It only raises an error when it gets to the elements it cannot convert.
At the end of the day, the best solution is to make sure all data types are the same. In your case, you could just list the numbers as a string:
WHEN #Month IN ('Aug','August','8') THEN 1
^^^^^

All the elements in the IN-list have to be of a type where implicit conversion is possible. You cannot convert a varchar value to an integer one, but the other way round. So try this statement.
CREATE FUNCTION dbo.fn_AcMonthOrder
(
#Month varchar(100)
)
RETURNS INT AS
BEGIN
DECLARE #MonthOrder Int
SET #MonthOrder =
(CASE
WHEN #Month IN ('Aug','August','8') THEN 1
WHEN #Month IN ('Sep','September','9') THEN 2
WHEN#Month IN ('Oct','October','10') THEN 3
ELSE 0
END)
RETURN #MonthOrder
END

When you use IN clause you should use one DataType now your are using 'Aug' near 8, and it assumes that it should convert 'aug',... to int it is incorrect.
you can write it in this way (Do it for all you Case Whens)
WHEN #Month IN ('Aug','August','8') THEN 1
.....

WHEN #Month IN ('Aug','August','8') THEN 1
WHEN #Month IN ('Sep','September','9') THEN 2
WHEN#Month IN ('Oct','October','10') THEN 3
Enclose in single quotes month values in numbers eg change 8 to '8' .
This is because #Month is of VARCHAR() datatype and IN() clause requires values inside it must have compatible datatype conversion amongst them.

Related

Error converting varchar value to data type int

I am trying to concatenate two integer values with hyphen in between. So when I try to do the same, SQL gives me the error.
Conversion failed when converting the varchar value '30-45' to data type int.
NOTE:
Also, the second value for concatenation can be null so in that case, a hyphen should not be concatenated.
example
from1 = 30
to1 = 45
case
to1 is null
then from1
else CONCAT(from1, '-' + nullif(to1,'')) end
AS age
//This works but shows 3045 instead of 30-45.
concat(from, '-', to) AS age
//This doesn't work out as it gives the error 'Conversion failed when converting the varchar value '30-45' to data type int.'
Thanks for the help in advance and looking forward to it.
DECLARE #FROM INT=30;
DECLARE #TO INT=45;
SELECT CAST(#FROM AS VARCHAR(2))+'-'+CAST(ISNULL(#TO,'') AS VARCHAR(2));
SQL is trying to convert your phrase to int probably because it's part of CASE statement. It uses the first route to determine the output type.
In your case- you put NULL as the first route option in your CASE, so it is determined as int. try putting instead of it this: CAST(NULL AS VARCHAR(10))
It seems that for some reason you think that strings that contain mathematical expressions are resolved as said expression, not an as literal string. Thus if you have the varchar value '30-45' you think it'll return the int value -15; this isn't true. This in fact isn't true in any language, let alone T-SQL.
For what you have, in your ELSE the '-' isn't a minus... It's a string... - is a minus. If you want to substract a number from another then it's a basic maths expression: a - b. You're effectively doing CONVERT(varchar,a) + '-' + CONVERT(varchar,b)... Just have your ELSE as the following:
from1 - NULLIF(to1,0)
This will return NULL if from1 has the value NULL, or to1 has the value NULL or 0.
Please check below code. It's working
example
#from1 = 30
#to1 = 45
IF #to1 is null
SELECT #from1
ELSE
SELECT CONCAT(#from1, '-' , nullif(#to1,'')) as age

TSQL CASE unexpectedly processing multiple THEN statements

I have a simple SQL CASE statement that I am trying to interpret the datatype of a variable and then converting it to said format. I have the following sample:
DECLARE #P1 varchar(10) = '2';
SELECT CASE 1
WHEN ISNUMERIC(#P1) THEN (CAST(#P1 AS INT))
WHEN ISDATE(#P1) THEN (CAST(#P1 AS DateTime))
ELSE 'N' END AS Test2P1
I would expect it to return an integer value of 2. However, this is what I get.
Test2P1
1900-01-03 00:00:00.000
However, if I modify the code to just display a character instead of CASTING the variable, I get a different result:
DECLARE #P1 varchar(10) = '2';
SELECT CASE 1
WHEN ISNUMERIC(#P1) THEN 'I'
WHEN ISDATE(#P1) THEN 'D'
ELSE 'N' END AS Test2P1
Then I get a result of: I
Taking this experiment one step further, if I leave the first test returning an 'I' but casting the date, then I get an error:
DECLARE #P1 varchar(10) = '2';
SELECT CASE 1
WHEN ISNUMERIC(#P1) THEN 'I'
WHEN ISDATE(#P1) THEN (CAST(#P1 AS DateTime))
ELSE 'N' END AS Test2P1
Msg 241, Level 16, State 1, Line 3
Conversion failed when converting date and/or time from character string.
It appears that SQL is evaluating multiple instances of THEN statements. However, the ISDATE expression does NOT return true. I am stumped.
In my research, I came across this article [SQL Performance] (https://sqlperformance.com/2014/06/t-sql-queries/dirty-secrets-of-the-case-expression) What he is saying in this article makes complete sense. But I do not see where it applies in this situation as I am never changing the value of the variable.
I have also wrapped my CASE statement in COALESCE(), but it does not appear to help. I wouldn't have expected it to, but I found multiple articles referencing this as a solution to similar problems. This seems like a very simple CASE statement, but I do not know where I am going wrong. Any help is greatly appreciated.
DateTime has a higher datatype precedence in SQL Server than INT does, so your whole CASE is getting cast as DATETIME. You can only return data of a single datatype in one column, thus the need for datatype precedence.
Here is the MSDN article showing precedence.
Although I can't think of a good reason to do this, you could force the case expression to return sql_variant, which can store multiple different types, eg:
DECLARE #P1 varchar(10) = '2';
SELECT CASE 1
when 0 then cast(null as sql_variant)
WHEN ISNUMERIC(#P1) THEN (CAST(#P1 AS INT))
WHEN ISDATE(#P1) THEN (CAST(#P1 AS DateTime))
ELSE 'N' END AS Test2P1

Why is SQL Server trying to convert my nvarchar(20) datatype to an int?

I'm getting the "conversion" error in a SQL Select query.
The error is:
Msg 248, Level 16, State 1, Line 6
The conversion of the nvarchar value '7000952682' overflowed an int column.
Problem is, there are no int columns in my table!
Here is the table structure:
Here is the query:
If I set the value of #SU to NULL, then it does return all rows as expected. When the value is set to the string value of '7000952682' I get the error.
Why is SQL Server trying to convert the nvarchar value to an int?
All branches of a CASE expression have to have the same type. In this case (no pun intended), it looks like SQL Server is using an integer type and doing an implicit cast of SU to integer. The problem is that the max value for an integer in SQL Server is roughly 2.1 billion, and the example you gave is using the value 7000952682, hence the overflow.
You have two options here. You could make everything varchar:
CASE WHEN #SU IS NULL OR #SU = '' THEN '1' ELSE [SU] END
Or, you could make everything numeric, using a type that won't overflow, e.g.
CASE WHEN #SU IS NULL OR #SU = ''
THEN CAST(1 AS numeric(20, 6))
ELSE CAST([SU] AS numeric(20, 6)) END
As a side note, you could write the first part of your CASE expression more succinctly using COALESCE:
CASE WHEN COALESCE(#SU, '') = '' THEN '1' ELSE [SU] END
Don't use case in the where clause. The logic is more simply and accurately expressed as:
where (#su is null or #su = '' or #su = su)

SQL "select case" gives unexpected output

For the love of god can someone please explain me what is going on here.
I am working on some stored procedure bug fixes, after a lot of struggle, I was able to find out where this strange bug is happening so I've made a simple example for the sake of demonstration.
Case 1
DECLARE #test VARCHAR(45) ='0001'
SELECT CASE 0
WHEN -1 THEN ''
WHEN 0 THEN #test
WHEN 1 THEN 12345
END AS 'output'
Case 2
DECLARE #test VARCHAR(45) ='0001'
SELECT CASE 0
WHEN -1 THEN ''
WHEN 0 THEN #test
END AS 'output'
Case 1: output is 1
Case 2: output is 0001 as expected
What happened to the zeros?
strangely it only removes zeros before the number (no matter what number comes at the end), for example DECLARE #test VARCHAR(45) ='1000' works fine, as far case is concerned it is clear that case is zero, if I remove WHEN 0 THEN #test output is null as expected.
Done some research, found only this.
I am using SQL SERVER RC1 2017 as well as SQL SMS.
Thank you for your time.
The difference here is that you have mutliple data types in your THEN/ELSE expressions. In your "CASE 1" you have both int and and varchar datatypes.
int has a higher Data type precedence (Transact-SQL) than a varchar, so the values are returned as an int.
Use the same datatype through out, and this works as you want it to:
DECLARE #test VARCHAR(45) ='0001';
SELECT CASE 0 WHEN -1 THEN ''
WHEN 0 THEN #test
WHEN 1 THEN '12345' --Note that the value in contained in single quotes
END AS [output];
This is because of data type precedence.
The CASE expression documentation says about the returned data type:
Returns the highest precedence type from the set of types in
result_expressions and the optional else_result_expression
Meaning it looks every set of types in the result expressions. Since you have one where the returned data is an INT, then the result of the whole CASE expression is INT (since it has a higher precedence than VARCHAR)
This is happening because the type of the value returned in your last case statement is numeric, so try to change it to
DECLARE #test VARCHAR(45) ='0001'
SELECT CASE 0
WHEN -1 THEN ''
WHEN 0 THEN #test
WHEN 1 THEN '12345'
END AS 'output'

using ISNUMERIC() with sql_variant SQL Server

How can I use ISNUMERIC() function with sql_variant datatype?
This following code doesn't work
DECLARE #x sql_variant
SET #x = 3
IF ISNUMERIC(#x) = 1
SELECT 'Numeric'
ELSE
SELECT ' NOT'
Error :
Msg 8116, Level 16, State 1, Line 4
Argument data type sql_variant is invalid for argument 1 of isnumeric function.
But this works
IF ISNUMERIC(CAST(#x AS INT)) = 1
is there is any way of making this happened with out CAST()
Haven't found any thing useful on google regarding this issue thanks , I'm using
SQL Server 2008 R2
If you want to know if the underlying datatype is numeric, you can use SQL_Variant_Property to find out;
DECLARE #x sql_variant
SET #x = 3.2
SELECT CASE
WHEN SQL_Variant_Property(#x, 'Precision') = 0
THEN 'NO'
ELSE 'YES'
END
Casting to int doesn't really make sense. Your conversion will fail (when something else than an integer appears) and you'll get an error.
You can, however, cast to nvarchar(max) - this should always work and your ISNUMERIC function will behave as expected