views:

547

answers:

4

I writing a SP that accepts as parameters column to sort and direction.

I don't want to use dynamic SQL.

The problem is with setting the direction parameter.

This is the partial code:

SET @OrderByColumn = 'AddedDate'
SET @OrderDirection=1;
.
.
.
 ORDER BY 
      CASE WHEN @OrderByColumn='AddedDate' THEN CONVERT(varchar(50),AddedDate)          
           WHEN @OrderByColumn='Visible' THEN CONVERT(varchar(2), Visible)    
           WHEN @OrderByColumn='AddedBy' THEN AddedBy   
           WHEN @OrderByColumn='Title' THEN Title    
      END
+1  A: 

Here is an example:

CREATE PROCEDURE GetProducts 
( 
    @OrderBy      VARCHAR(50), 
    @Input2       VARCHAR(30) 
) 
AS 
BEGIN 
    SET NOCOUNT ON 

    SELECT Id, ProductName, Description, Price, Quantity 
    FROM Products 
    WHERE ProductName LIKE @Input2 
    ORDER BY 
        CASE             
            WHEN @OrderBy = 'ProductNameAsc' THEN ProductName 
        END ASC, 
        CASE 
            WHEN @OrderBy = 'ProductNameDesc' THEN ProductName 
        END DESC 

END

From here:

http://www.dominicpettifer.co.uk/Blog/21/dynamic-conditional-order-by-clause-in-sql-server-t-sql

Ascending and Descending actions need to be grouped into separate CASE statements, separated with a comma. In your server-side code/script make sure to append 'Asc' or 'Desc' onto the order by string, or you could have two Stored procedure input parameters for column name and order by direction if you want.

Alex Black
can you please explain this END ASC, (comma) CASE syntax? If the input is ProductNameDesc, Won't it generate: .. ORDER BY ASC, ProductName DESC ? the "asc," following the end is the part of statement isn't it? – markiz 0 secs ago [delete this comment]
markiz
I don't actually know, I just googled to find that article. Gary's response below seems to use the same technique.
Alex Black
hey markiz, you should just *try* it. You're basically saying you don't believe that what this article suggests will work, so just give it a go, I bet it will work just fine.
Alex Black
it works, but i want to understand why.
markiz
Presumably the logic goes something like this: Each CASE statement is evaluated, if none of the WHEN statements in the CASE statement are triggered then the entire CASE statement is ignored, including the trailing ASC.
Alex Black
Shannon Severance
@Shannon: thx, that makes more sense.
Alex Black
thank you Shannon
markiz
+5  A: 

You could have two near-identical ORDER BY items, one ASC and one DESC, and extend your CASE statement to make one or other of them always equal a single value:

ORDER BY 
      CASE WHEN @OrderDirection=0 THEN 1
      ELSE
           CASE WHEN @OrderByColumn='AddedDate' THEN CONVERT(varchar(50),AddedDate)          
                WHEN @OrderByColumn='Visible' THEN CONVERT(varchar(2), Visible)    
                WHEN @OrderByColumn='AddedBy' THEN AddedBy           
                WHEN @OrderByColumn='Title' THEN Title
           END
      END ASC,
      CASE WHEN @OrderDirection=1 THEN 1
      ELSE
           CASE WHEN @OrderByColumn='AddedDate' THEN CONVERT(varchar(50),AddedDate)          
                WHEN @OrderByColumn='Visible' THEN CONVERT(varchar(2), Visible)    
                WHEN @OrderByColumn='AddedBy' THEN AddedBy           
                WHEN @OrderByColumn='Title' THEN Title
           END
      END DESC
Gary McGill
can you please answer the same question i asked Alex Black in comment?
markiz
You're just doing ORDER BY Column1 ASC, Column2 DESC (meaning order by Column1 ascending, then by Column2 descending) but instead of Column1 and Column2 you've got an expression for each.
Gary McGill
if AddedDate is a datetime column you must use _CONVERT(char(23),AddedDate,121)_ or it will not sort properly
KM
A: 

hope this link will guide you

anishmarokey
Actually, his posts aren't very good.
gbn
+1  A: 

You can simplify the CASE by using ROW_NUMBER which sorts your data and effectively converts it into a handy integer format. Especially since the question is tagged SQL Server 2005

This also expands easily enough to deal with secondary and tertiary sorts

I've used multiplier to again simplify the actual select statement and reduce the chance of RBAR evaluation in the ORDER BY

DECLARE @multiplier int;

SELECT @multiplier = CASE @Direction WHEN 1 THEN -1 ELSE 1 END;

SELECT
     Columns you actually want
FROM
    (
    SELECT
         Columns you actually want,
         ROW_NUMBER() OVER (ORDER BY AddedDate) AS AddedDateSort,
         ROW_NUMBER() OVER (ORDER BY Visible) AS VisibleSort,
         ROW_NUMBER() OVER (ORDER BY AddedBy) AS AddedBySort,
         ROW_NUMBER() OVER (ORDER BY Title) AS TitleSort
    FROM
         myTable
    WHERE
         MyFilters...
    ) foo
ORDER BY
     CASE @OrderByColumn
        WHEN 'AddedDate' THEN AddedDateSort
        WHEN 'Visible' THEN VisibleSort    
        WHEN 'AddedBy' THEN AddedBySort
        WHEN 'Title' THEN TitleSort
     END * @multiplier;
gbn