SQL Server CASE in ORDER BY clause in stored procedure - sql

I have this ORDER BY clause here:
ORDER BY
CASE WHEN #isAlphabeticalSort = 1 THEN itemName ELSE itemId END
I have #isAlphabeticalSort defined in my stored procedure like so:
#isAlphabeticalSort bit = 1
When I run my stored procedure with #isAlphabeticalSort set to 0:
#isAlphabeticalSort = 0
It works as expected, when I set it to 1 when I run my stored procedure, I get this error:
Conversion failed when converting date and/or time from character string. Warning: Null value is eliminated by an aggregate or other SET operation.
I also have the red line under #isAlphabeticalSort = 0 says:
#isAlphabeticalSort is not a parameter in the procedure
My question is, am I defining my bool wrong? Is my case in my order by clause wrong? What am I doing wrong?

When using a CASE expression, the datatype that is attempted to be returned with be the datatype with the highest data type precedence. In this case you have 2 columns in your CASE expression itemName (which I assume is a varchar) and itemID (which I assume in an datetime). datetime has a higher precendence, so any return values will be implicitly converted to an datetime, if they aren't already.
The correct way, therefore, to do this would be:
ORDER BY CASE WHEN #isAlphabeticalSort = 1 THEN itemName END,
CASE WHEN #isAlphabeticalSort = 0 THEN itemId END, --As recommended by #JamesZ
[Other Columns];
For reference:
Data Type Precendence (Transact-SQL) and
CASE (Transact-SQL): Return Types

Both columns need to have the same type, you can try something like this
ORDER BY CASE WHEN #isAlphabeticalSort = 1 THEN itemName
ELSE CONVERT(varchar(10), itemId, 102) -- as recommended by Lamu
END

The error is due to your columns itemName (varchar ?) and itemId (int ?). You can only use the same datatype in Case statement.
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/case-transact-sql#arguments
"The data types of else_result_expression and any result_expression must be the same or must be an implicit conversion."

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

Sql ISNUMERIC()

SELECT CASE WHEN ISNUMERIC('1a') =1 THEN 1 ELSE 'A' END
i'am getting this error !!
Conversion failed when converting the varchar value 'A' to data type int.
you are a victim of data type precedence.Taken from BOL:
When an operator combines two expressions of different data types, the rules for data type precedence specify that the data type with the lower precedence is converted to the data type with the higher precedence. If the conversion is not a supported implicit conversion, an error is returned. When both operand expressions have the same data type, the result of the operation has that data type
So in your case ,CASE is an expression and when two or more data types are combined in this expression,it returns data type of highest precedence..in your case it is INT..So change your query to below
SELECT CASE WHEN ISNUMERIC('1a') =1 THEN cast(1 as varchar) ELSE 'A' END
SELECT CASE WHEN ISNUMERIC('1a') =1 THEN 1 ELSE 2 END
SELECT CASE WHEN ISNUMERIC('1A') = 1 THEN '1' ELSE 'A' END
OR
SELECT CASE WHEN ISNUMERIC('1A') =1 THEN '1' ELSE SUBSTRING('1A',2,2) END

Case statement in where clause not working

Friends..
I am using stored procedure in which there is an optional parameter #equal and default value is NULL. If user give some value to the parameter SQL query has to be changed. I am trying to use Case in Where clause. but its showing some error.
Help me with proper syntax or with better logic
My requirement is When user doesn't give value for #equal then
FiscalYear<#yr
Else
FiscalYear<=#yr
Select BankCode,(SUM(Debit)-SUM(Credit)) Amt
From vwDailyData
Where Pname=#ParishName and FiscalYear< (CASE WHEN #equal IS NULL THEN #yr ELSE '='+#yr)
and BankCode<>'Cash'
Group By BankCode
Modified Question
Select BankCode,(SUM(Debit)-SUM(Credit)) Amt
From vwDailyData
Where Pname=#ParishName AND (CASE WHEN #equal IS NULL THEN FiscalYear < #yr ELSE FiscalYear <= #yr END)
and BankCode<>'Cash'
Group By BankCode
Error statement
Msg 102, Level 15, State 1, Procedure spDisplayBankConsolidate, Line 14
Incorrect syntax near '<'.
You have two errors in your condition:
CASE expression lacks END, and
You cannot supply a different operator inside a CASE expression.
The condition should look like this:
WHERE Pname=#ParishName AND
((#equal IS NULL AND FiscalYear < #yr) OR (#equal IS NOT NULL AND FiscalYear <= #yr))
AND BankCode<>'Cash'
Note the #equal IS NULL and #equal IS NOT NULL conditions in two parts of the OR expression. Since the two are mutually exclusive, only one side of the OR will be deciding what rows to include in the query result.

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

select case statement error in mssql

SELECT top 1
case
when VR = -99999.99
then 0
else cast((VR*1.732) as decimal(38,3))
end
FROM pseb.dbo.datasource
where FeederID=5003
order by datetime desc
The above query is working fine, but I need to return varchar value '--' instead of returning 0
if I do like that
SELECT top 1
case
when VR = -99999.99
then '--'
else cast((VR*1.732) as decimal(38,3))
end
FROM pseb.dbo.datasource
where FeederID=5003
order by datetime desc
means it returns the following error:
Msg 8114, Level 16, State 5, Line 1 Error converting data type varchar
to numeric.
please help me to solve it
The problem is that you are returning two different data types from the same column. The rule with SQL Server that numeric types take precedence over string types, i.e. in a situation like yours a string gets converted to a number, not the other way around.
So to solve this you can cast your number to a string.
One option is to do something like this:
SELECT top 1
case when VR = -99999.99 then '--'
else
cast
(
cast((VR*1.732) as decimal(38,3)
)
as varchar(50))
end
FROM pseb.dbo.datasource where FeederID=5003 order by datetime desc