Dynamic ASC and DESC and Order by DateTime

by Allan Svelmøe Hansen December 07, 2007 10:44

Occasionally I have the problem that I need to run as query with a form of dynamic sorting - meaning sometimes ascending or descending and sometimes based on an ordernumber or a date, for example.

Now a CASE statement in the order by is often very effective for handeling such issues, but I've not found it possible to combine it with the Ascending and Descending clasuses (yet, could be that I'm just doing it wrong). 

For example suppose we have a table which contains a "Date" field of the type DateTime, and we need to be able to sort this both descending and ascending based on some input parameter. Instead of making two queries, one might think that something like this would work

DECLARE @ASC BIT
SET @ASC = 1

SELECT *
FROM DateTimeOrderTest
ORDER BY DATE
    CASE @ASC
        WHEN 1 THEN ASC
        ELSE DESC
    END

But well - it doesn't: "Incorrect syntax near the keyword 'CASE'."

Or one might think:

DECLARE @ASC BIT
SET @ASC = 1
SELECT *
FROM DateTimeOrderTest
ORDER BY
    CASE @ASC
        WHEN 1 THEN Date ASC
        ELSE Date DESC
    END

Which gives a nice little: Incorrect syntax near the keyword 'ASC'

A little fix to get around this would be to not utilize case, but instead make the Ascending and Descending a factor so when Ascending you have a factor of 1 and Descending you have a factor of -1. Then simply convert/cast the Date to an integer (which should not be a terrible expensive procedure, as the datetime is represented as a number anyway, I wonder if it is possible to somehow use the internal representation for my purpose, or if the database does that when casting as integer....oh, well), and multiply the factor to the order by.

This mean the following two queries give the same result:

SELECT  *
FROM DateTimeOrderTest
ORDER BY
CAST(Date AS INT) * -1

SELECT *
FROM DateTimeOrderTest
ORDER BY
Date DESC

This technique of multiplying either 1 or -1, can be used in many queries, and of course is not limited to datetimes.

Anyways, I've found it quite useful myself. 

Bookmark and Share DotnetKicks dotnetshoutout

Comments

12/9/2007 1:15:23 PM #

Try to look at http://www.sqlteam.com/article/dynamic-order-by
The solution might be there.

Morten Knudsen

12/9/2007 5:01:23 PM #

The article linked is not handling the same issue as I mention here. The sql-team is about using a case to simply select between a number of fields.
However it doesn't describe the dynamic usage of asc and desc in the same query, which was one of the main points of this one.
Case is a powerful utility, but not being able to use case for asc and desc makes it necessary to implement workarounds like this one.

Allan S. Hansen

5/27/2008 4:01:54 PM #

DECLARE @ASC BIT
SET @ASC = 1
SELECT *
FROM DateTimeOrderTest
ORDER BY
    CASE @ASC
        WHEN 1 THEN Date ASC
        ELSE Date DESC
    END
You have error in your query correct query is:
DECLARE @ASC BIT
SET @ASC = 1
SELECT *
FROM DateTimeOrderTest
ORDER BY
    CASE
        WHEN @ASC=1 THEN (RANK() OVER (ORDER BY Date ASC))
        WHEN @ASC=2 THEN (RANK() OVER (ORDER BY Date DESC))
    END

tarek yehya Egypt

5/29/2008 6:45:16 AM #

Thank you for your comment.
Yes, I know the query has an error in it, because I also mention in the blog post, that it would give an "incorrect syntax near asc" error message. It is used for illustration.


The issue with your replacement query is that it is significantly slower (and much more complex) then just casting the datetime as an integer, and then multiplying either -1 or 1 to simulate the sorting direction.

Allan S. Hansen Denmark

6/6/2008 12:27:49 PM #

Hi there thanks for the above code realy great but can you maby help me with somthing read the folwing code in ms sql 2005

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go


ALTER PROCEDURE [dbo].[sp_system_Web_Tabel_Read_Last]
(
@Par_system_Table_Name VARCHAR(500)= af_17_12v_mon
)
AS
DECLARE @Value as varchar(500)

IF OBJECT_ID(@Par_system_Table_Name) IS NULL
RAISERROR('User table or view not found.',16,1)
SELECT @Value = 'SELECT TOP 1 * FROM ' + @Par_system_Table_Name(ORDER BY DateTime DESC)


exec(@Value

It gives me a esyntax error on order is there a difrent way to do this please email me on rynoeengelbrecht@webmail.co.za

Ryno South Africa

10/16/2008 7:10:00 AM #

Hi,

you can use the case statement like so:

ORDER BY
    CASE WHEN @ASC = 1 THEN Date END ASC,
    CASE WHEN @ASC <> 1 THEN Date END DESC

The ASC and DESC must come after the case statement

however this can still cause some issues if you wish to order by more than 1 field! - still haven't worked that one out yet Smile

Matt Australia

10/16/2008 4:43:27 PM #

Thanks for your input.
The "problem", so to speak, with your solution - outside the multiple fields one - is that you are "forced" to use multiple cases Smile

But I hadn't thought of using multiple cases in that manner, so it is worth a look at.

Thanks Smile

Allan S. Hansen Denmark

7/2/2009 10:37:36 PM #

Just wan to say thanks to tarek yehya for his solution.  Until there's  a way to flip +/- on dates this is helpful.

Allan, thanks for the site (tusind tak)

everett United States

10/13/2009 4:55:07 PM #

Interesting posts, bookmarked for future referrence

ekspekt

1/16/2010 10:30:53 AM #

Took me time to read all the comments, but I really enjoyed the article. It proved to be Very helpful to me and I am sure to all the commenters here! It's always nice when you can not only be informed, but also entertained! I'm sure you had fun writing this article.

Erasmo Talvy United Kingdom

5/11/2010 4:26:35 PM #

Matt > Thanks for an easy constructive way of solving this problem. Have tried on several occasions to find one without much luck!

Lars Sweden

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.6.1.0
Theme by Mads Kristensen | Modified by Mooglegiant

About:
Allan Svelmøe Hansen

My real name is Allan Svelmøe Hansen.
I live in Denmark, where I work as a developer for hedal:kruse:brohus using SQL Server and the .NET framework since 2004.
My primary fields of expertise is back-end data integration, database design and optimization.


       View Allan Svelmøe Hansen's profile on LinkedIn     

Disclaimer

The opinions expressed herein are my own personal opinions and thoughts and does not represent my employers view in any way, nor are my results guaranteed for all situations.
Content is presented "as is", with no warranty.