Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Order By in a stored procedure without using dynamic SQL

I've the following MS SQL stored procedure. I need to sort the results without using dynamic SQL and sp_executesql method

@Order by can have the possible values ProductName ASC, ProductName DESC, ProductCode ASC, VendorName DESC, VendorCode or ClientName

I was trying to use ORDER BY CASE, is there any issue if the ProductName, ProductCode are of different type?

ALTER PROCEDURE [dbo].[SortedReport]
(
    @ClientID INT,
    @RecordLimit,
    @FromDate DATETIME,
    @ToDate DATETIME,
    @OrderBy NVARCHAR(MAX)
)

AS
BEGIN

IF (@OrderBy IS NULL) BEGIN
    SET @OrderBy = 'ProductName';
END    

SELECT TOP (@RecordLimit) 
        sv.ClientID,
        sv.VendorID,
        sv.ProductID,
        sv.TransactionTime,
        sv.ClientName,
        sv.VendorName,
        sv.ProductName,
        sv.ProductCode,
        sv.VendorCode,
FROM SortedReportiew AS sv 
WHERE (sv.ClientID = @ClientID)
    AND (sv.TransactionTime >= @FromDate)
    AND (sv.TransactionTime < @Date)

Update:

Is the below part correct? ref from here

ORDER BY 
    CASE @OrderBy WHEN 'ProductCode ASC' THEN ProductCode WHEN 'ProductCode DESC' THEN ProductCode END DESC,
    CASE @OrderBy WHEN 'ProductName ASC' THEN ProductName WHEN 'ProductName DESC' THEN ProductName END DESC,
like image 958
Mithun Sreedharan Avatar asked May 17 '11 05:05

Mithun Sreedharan


People also ask

Can you use ORDER BY in a stored procedure?

Of course, we can certainly hard-code the ORDER BY clause in a stored procedure, but this approach becomes fixed in stone. We could try a dynamic SQL solution, involving a stored procedure code that dynamically builds and executes SQL Server statements inside a stored procedure.

What we can use instead of ORDER BY in SQL?

The ORDER BY statement in SQL is used to sort the fetched data in either ascending or descending according to one or more columns. By default ORDER BY sorts the data in ascending order. We can use the keyword DESC to sort the data in descending order and the keyword ASC to sort in ascending order.

Can we use ORDER BY without WHERE clause in SQL?

ORDER BY Characteristics: The ORDER BY clause is used to get the sorted records on one or more columns in ascending or descending order. The ORDER BY clause must come after the WHERE, GROUP BY, and HAVING clause if present in the query. Use ASC or DESC to specify the sorting order after the column name.

Can we use ORDER BY without SELECT?

Yes, you can order by a field(s)even if it is not your in your select statement but exists in your table. For a group by clause though you'd need it to be in your select statement. There's another exception, when you're using SELECT DISTINCT you must include the fields used in the GROUP BY clause in the select list.


2 Answers

As you already said: Use ORDER BY CASE, but multiple times to avoid the problems with different column types:

...
ORDER BY 
 CASE WHEN @OrderBy ='ProductName ASC' THEN sv.ProductName END,
 CASE WHEN @OrderBy ='ProductName DESC' THEN sv.ProductName END DESC,
 CASE WHEN @OrderBy ='ProductCode ASC' THEN sv.ProductCode END,
 CASE WHEN @OrderBy ='ProductCode DESC' THEN sv.ProductCode END DESC,
 CASE WHEN @OrderBy ='VendorName ASC' THEN sv.VendorName END,
 CASE WHEN @OrderBy ='VendorName DESC' THEN sv.VendorName END DESC,
 CASE WHEN @OrderBy ='VendorCode' THEN sv.VendorCode END,
 CASE WHEN @OrderBy ='ClientName' THEN sv.ClientName END

EDIT:

Updated the query to fit your updated question. I assume you meant ProductCode ASC and ProductCode DESC?

like image 78
Ocaso Protal Avatar answered Sep 28 '22 00:09

Ocaso Protal


I understand, the ordering uses just one column. In that case I might try something like this:

  1. Split @OrderBy into @OrderByCol and @OrderByDir.

  2. Use this template:

    ...
    ORDER BY
      CASE @OrderByDir WHEN 'ASC' THEN
        CASE @OrderByCol
          WHEN 'Column1' THEN Column1
          WHEN 'Column2' THEN Column2
          ...
        END
      END ASC,
    
      CASE @OrderByDir WHEN 'DESC' THEN
        CASE @OrderByCol
          WHEN 'Column1' THEN Column1
          WHEN 'Column2' THEN Column2
          ...
        END
      END DESC
    

    Or, if you are on SQL Server 2005+, maybe this one, as an alternative:

    WITH sorted AS (
      SELECT
         ... /* columns, omitted */
         Column1Order = ROW_NUMBER() OVER (ORDER BY Column1),
         Column2Order = ROW_NUMBER() OVER (ORDER BY Column2),
         ...
      FROM ...
    )
    SELECT ...
    FROM sorted
    ORDER BY
      CASE @OrderByCol
        WHEN 'Column1' THEN Column1Order
        WHEN 'Column2' THEN Column2Order
        ...
      END * CASE @OrderByDir WHEN 'DESC' THEN -1 ELSE 1 END
    

As @Greg Ogle has correctly pointed out in the comment, the first template can only work when the various sorting criteria are of compatible types, otherwise the statement will break.

like image 27
Andriy M Avatar answered Sep 27 '22 22:09

Andriy M