T-SQL Dealing with Null Values in an Order By Clause
Here's a cool technique that one of my coworkers and I came up with today for an issue I had with using "Order by" in a T-SQL query. Apparently SQL Server handles null values differently than other db's do (such as Oracle). In my case, I had a "rank" column in my table and wanted the results ordered by that rank. Unfortunately, my rank column also had some null values in it (I know there are different schools of thought on null values, but that's another issue for another time!). SQL server handles this by grouping the null values at the top of the result set, kinda like this:
----
null
null
null
1
2
3
So we kicked around a few ideas that I could use to turn that result set into this:
----
1
2
3
null
null
null
One idea was to create a procedure to pull the null results into a temp variable table and the non-null values into a separate temp variable table and then join the results into the final result set. Not a bad idea, but it seemed like too much work.
Another idea was to evaluate the rank column within a case statement in the select like so:
CASE
when rank is not null then rank
when rank is null then 9999
else null end as rank
FROM blah
ORDER by rank
Not a bad idea, but I still didn't really care for that solution either. The whole idea of hardcoding a value in to represent the null values didn't sit well with me.
The next idea was to use the SQL isnull function within the order by like this:
FROM blah
ORDER by isnull(rank, 99999)
I liked this solution much better than the previous ideas, but it was still hardcoding the null values. If you're still reading this, trust me, I'll get to the point soon :) - So here was my next idea, how about a subquery to determine the maximum possible rank, then add 1. Pretty dynamic, no hardcoding:
FROM blah
ORDER by isnull(rank, (SELECT max(rank)+1 FROM BLAH))
A pretty solid solution in my opinion, but my coworker brought up a good point. This solution would run the subquery for each row in the query, thus adding unneccessary proccessing time. So, why not do the query once and set in a variable? Here's the final solution:
declare @maxrank int
--store the max rank +1 in that variable
select @maxrank = max(rank)+1 FROM BLAH
SELECT rank
FROM blah
ORDER by isnull(rank, @maxrank)
So there it is. An efficient, dynamic solution to ordering a result set which puts the null values AFTER the non-nulls.



Stupid ms sql server and its sorting.
E.g. if rank is an int, then ISNULL(rank, 2147483647)
(Granted it would still be better if SQL Server had constants, or something like int.maxValue)
Thanks!
SELECT rank
FROM blah
ORDER BY (CASE WHEN rank IS NULL THEN 1 ELSE 0 END), rank