SQL error in CASE expression - sql

SELECT DISTINCT
AM.programid,
AM.ProjectNumber,
AM.AppID,
AM.DateCreated,
CASE WHEN AM.applicationentryflag = 210
AND YEAR(App646.Application_Received_Date) = CONVERT(INT,#PY)
THEN CAST(CONVERT(VARCHAR(10),App646.Application_Received_Date,101) AS DATETIME)
WHEN AM.applicationentryflag <> 210
AND YEAR(AM.datecreated) = CONVERT(INT,#PY)
THEN CAST(CONVERT(VARCHAR(10),AM.datecreated,101) AS DATETIME)
END AS [Date_App_Rec]
I get the following error when executing this code:
At least one of the result expressions in a CASE specification must be
an expression other than the NULL constant.

This error occurs when SQL can't infer a type, which means that all results in one of your case expressions are null for example:
SELECT CASE WHEN 1 = 0 THEN NULL ELSE NULL END
I tested your Case statement with a static date and it doesn't seem to have a problem. (However, I am not sure why you would convert date to varchar(10) then back to DATETIME)
SELECT CAST(CONVERT(VARCHAR(10),'2017-08-31',101) AS DATETIME)
SELECT CAST(CONVERT(VARCHAR(10),'2017-08-31',101) AS DATETIME)
so I doubt the error is from the code you have shown us.

Related

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 string '00000' displaying as '0'

Can someone explain why
CASE
WHEN MARK = 'Y'
THEN LEFT('00000', 5-LEN(DATEDIFF(MINUTE, START, FINISH))) + DATEDIFF(MINUTE, START, FINISH)
ELSE '00000'
END AS [Time]
Is displaying as a single 0 instead of 00000 when Mark <> 'Y', and displaying 35 instead of 00035 (as an example)
I would guess SQL is converting it to an integer.
Code like this select cast('00000' as varchar) returns as you wish (00000, 00035) but select cast('00000' as int) returns your results (0, 35 etc)
My understanding is that you are using MSSQL server. If, yes then the default datatype for any variable or nullable column is INT

sql inconsistent datatypes: expected number got char

I am trying to write a Case When statement, but I get an inconsistent datatypes error. I need 'Returned' displayed if the first when statement is not met.
CASE
WHEN (X.RECEIVED_QTY = 0) THEN FLOOR(SYSDATE-INVENTORY_TRANS.TRANSACTION_DATE)
WHEN (X.RECEIVED_QTY = 0) THEN 'RETURNED'
END AS DAYS_OUT
You can't mix results of a CASE statement, that means you can't return an INT under one condition and a VARCHAR in another. If you want to return Returned then you will need to CONVERT or CAST your numeric values to VARCHAR
You also have a syntactical problem with your CASE.
You'd have to change it to something like this:
CASE X.RECEIVED_QTY
WHEN 0 THEN CAST( FLOOR(SYSDATE-INVENTORY_TRANS.TRANSACTION_DATE) AS VARCHAR(20))
ELSE 'RETURNED'
END AS DAYS_OUT

Specify order of (T)SQL execution

I have seen similar questions asked elsewhere on this site, but more in the context of optimization.
I am having an issue with the order of execution of the conditions in a WHERE clause. I have a field which stores codes, most of which are numeric but some of which contain non-numeric characters. I need to do some operations on the numeric codes which will cause errors if attempted on non-numeric strings. I am trying to do something like
WHERE isnumeric(code) = 1
AND CAST(code AS integer) % 2 = 1
Is there any way to make sure that the isnumeric() executes first? If it doesn't, I get an error...
Thanks in advance!
The only place order of evaluation is guaranteed is CASE
WHERE
CASE WHEN isnumeric(code) = 1
THEN CAST(code AS integer) % 2
END = 1
Also just because it passes the isnumeric test doesn't guarantee that it will successfully cast to an integer.
SELECT ISNUMERIC('$') /*Returns 1*/
SELECT CAST('$' AS INTEGER) /*Fails*/
Depending upon your needs you may find these alternatives preferable.
Why not simply do it using LIKE?:
Where Code Not Like '%[^0-9]%'
Btw, either using my solution or using IsNumeric, there are some edge cases which might lead one to using a UDF such as 1,234,567 where IsNumeric will return 1 but Cast will throw an exception.
Why not use a CASE statement to say something like:
WHERE
CASE WHEN isnumeric(code) = 1
THEN CAST(code AS int) % 2 = 1
ELSE /* What ever else if not numeric */ END
You could do it in a case statement in the select clause, then limit by the value in an outer select
select * from (
select
case when isNum = 1 then CAST(code AS integer) % 2 else 0 end as castVal
from (
select
Case when isnumeric(code) = 1 then 1 else 0 end as isNum
from table) t
) t2
where castval = 1