Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding a Sql Server Query - CASE within an ORDER BY clause

I'm trying to mess around with putting CASE statement in the ORDER BY clause using a DISTINCT in the SELECT list, and finding some odd behavior that I don't understand. Here is some code:

select distinct Requester, ISO_ID as ISO, (ISO_ID - 5 + 50) AS 'someNum', BU
from LoanerHeader order by
CASE WHEN 'a' = 'b' then Requester
when 'b' = 'c' then BU
else ISO_ID
end

This works. But if I change the 4th line to when 'b' = 'b' then BU:

select distinct Requester, ISO_ID as ISO, (ISO_ID - 5 + 50) AS 'someNum', BU
from LoanerHeader order by
CASE WHEN 'a' = 'b' then Requester
when 'b' = 'b' then BU
else ISO_ID
end

it breaks with error:

ORDER BY items must appear in the select list if SELECT DISTINCT is specified.

When BU is obviously in the select list. Even stranger is when I change the code to:

select distinct Requester, ISO_ID as ISO, (ISO_ID - 5 + 50) AS 'someNum', BU
from LoanerHeader order by
CASE WHEN 'a' = 'b' then Requester
when 'b' = 'b' then BU
else BU   --change is here
end

It works again! How does that even make sense? Can someone help me wrap my brain around this one?

like image 437
Nick Rolando Avatar asked Nov 09 '11 19:11

Nick Rolando


People also ask

Can we use CASE statement in ORDER BY clause in SQL Server?

Nope! Although it is most often used there, CASE is not limited to SELECT statements. For example, you can use it in clauses like IN , WHERE , HAVING , and ORDER BY .

How do you use a case in ORDER BY clause?

How to use CASE with ORDER BY clause in SQL Server? To do this, we use the CASE after ORDER BY and then checks for column value. In above case, all records having Active = 1 is sorted on “Active ASC” order. All records having Active = 0 is sorted on 'LastName DESC' else 'FirstName DESC' order.

How do you get query results in the same order as given in clause?

in php u can do it like : <? php $my_array = array (3,6,1,8,9) ; $sql = 'SELECT * FROM table WHERE id IN (3,6,1,8,9)'; $sql . = "\nORDER BY CASE id\n"; foreach($my_array as $k => $v){ $sql .

Can we use CASE statement in FROM clause?

No, you can't pick a table to query using a CASE statement. CASE statements only go within expressions, such as for a column's value or as part of your WHERE expression.


1 Answers

The rules for CASE are that the result should be cast to the datatype of the branch with highest precedence.

For the first query it uses contradiction detection and just generates a plan that sorts by ISO_ID directly. This is numeric already so no need to implicitly cast and so matches the expression in the select list with no problem.

For the second query it can again determine at compile time that it needs to ORDER BY BU. Except it actually needs to ORDER BY CAST(BU AS NUMERIC) due to the above. This means it would need to ORDER BY a computed expression not matching anything anything in the SELECT list. Hence the problem.

Your third query removes the expression of higher precedence from the CASE thus removing the need for an implicit cast (and hence the need to order by a computed expression).

As the computed expression is entirely dependant upon the columns in the SELECT DISTINCT list however you could rewrite the second query as follows.

;WITH CTE AS
(
SELECT DISTINCT Requester,
                ISO_ID              AS ISO,
                ( ISO_ID - 5 + 50 ) AS 'someNum',
                BU
FROM   LoanerHeader
)
SELECT *
FROM CTE
ORDER  BY CASE
            WHEN 'a' = 'b' THEN Requester
            WHEN 'b' = 'b' THEN BU
            ELSE ISO
          END
like image 91
Martin Smith Avatar answered Oct 12 '22 21:10

Martin Smith