How To Implement Conditional Order By in SQL
Lately I have been working on a project where a client requested a data to be returned in a sorted order with the flexibility of being able to select a column which they wanted the data to be sorted by. This option, using pure vanilla T-SQL is rather complex to achieve using T-SQL as writing a stored procedure that, for example, underpins the SSRS report in the following fashion will not work.
CREATE PROCEDURE dbo.Sort_Dynamically @SortColumn NVARCHAR (100), @SortDirection VARCHAR (4) AS BEGIN ... ORDER BY @SortColumn, @SortDirection END GO
There are few different approaches that could provide the flexible sorting functionality, so let’s start with putting together a sample data set we can execute the SQL code against.
USE MASTER GO IF (EXISTS(SELECT Name FROM SysDatabases WHERE name = 'SortDB' )) BEGIN ALTER DATABASE [SortDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE DROP DATABASE [SortDB] END GO CREATE DATABASE SortDB GO USE SortDB GO IF EXISTS (SELECT * FROM SortDB.dbo.sysobjects o WHERE o.xtype in ('U') and o.id = object_id(N'sortdb..temp_Table')) DROP TABLE Temp_Table GO SELECT TOP 1000 key_col = ROW_NUMBER() OVER (ORDER BY s1.[object_ID]), object_id = s1.[object_id], name = s1.name COLLATE DATABASE_DEFAULT, object_tp_description = s1.type_desc COLLATE DATABASE_DEFAULT, modify_date = s1.modify_date INTO Temp_Table FROM sys.all_objects AS s1 ORDER BY s1.[object_id];
Given that we now have five attributes to potentially order by, let’s assume that all these will participate in the user selection option. Additionally, the user will want to ensure that the sort order will be one of the inputs/parameters so all data can be sorted in either ascending or descending order. To accomplish this requirement I have two separate methods which can produce the required data sets – one using dynamic SQL and another using window function.
DYNAMIC SQL METHOD
CREATE PROCEDURE dbo.Sort_Dynamically_dSQL @SortColumn NVARCHAR (128), @SortDirection VARCHAR (4) AS BEGIN SET NOCOUNT ON; --ENSURE THAT CORRECT SORTING DIRECTION IS ENTERED IF UPPER(@SortDirection) NOT IN ('ASC', 'DESC') BEGIN RAISERROR('Invalid entry for @SortDirection: %s', 11, 1, @SortDirection); RETURN -1; END --ENSURE THAT CORRECT COLUMN NAME IS ENTERED IF LOWER(@SortColumn) NOT IN ('key_col', 'object_id', 'name', 'object_tp_description', 'modify_date') BEGIN RAISERROR ('Invalid entry for @SortColumn: %s', 11, 1, @SortColumn); RETURN -1; END SET @SortColumn = QUOTENAME(@SortColumn); DECLARE @Sql NVARCHAR (MAX) SET @Sql = 'SELECT key_col, object_id, name, object_tp_description, modify_date FROM Temp_Table ORDER BY' + @SortColumn + '' + @SortDirection + ';' EXEC sp_executesql @Sql END
This dynamic SQL encapsulated in a stored procedure with a few validation lines is pretty self-explanatory. It dynamically creates a SELECT statement based on the two variables entered as per below. Window function method, again encapsulated in a stored procedure, uses a different approach where sorting is done by means of ROW_NUMBER() function, whereas sort direction is the result of a simple multiplication to determine if the order should be ascending or descending as per the code below.
WINDOW FUNCTION METHOD
CREATE PROCEDURE dbo.Sort_Dynamically_RowNumber @SortColumn NVARCHAR (128), @SortDirection VARCHAR (4) AS BEGIN SET NOCOUNT ON; WITH x AS (SELECT key_col, object_id, name, object_tp_description, modify_date, rn = ROW_NUMBER() OVER(ORDER BY CASE @SortColumn WHEN 'key_col' THEN RIGHT ('000000000000' + RTRIM (key_col),12) WHEN 'object_id' THEN RIGHT(COALESCE(NULLIF(LEFT(RTRIM(object_id),1),'-'),'0') + REPLICATE ('0',23) + RTRIM(object_ID),24) WHEN 'key_col' THEN RIGHT (RTRIM (key_col),12) WHEN 'object_id' THEN RIGHT(RTRIM(object_ID),24) WHEN 'name' THEN name WHEN 'object_tp_description' THEN object_tp_description WHEN 'modify_date' THEN CONVERT (VARCHAR(25), modify_date, 120) END) * CASE @SortDirection WHEN 'ASC' THEN 1 ELSE -1 END FROM Temp_Table) SELECT key_col, object_id, name, object_tp_description, modify_date FROM x ORDER BY rn END
Now we can execute any of the two stored procedures with parameters assigned as per the column we wish to sort by and the sort order i.e. ascending or descending.
--SORT BY key_col column IN DESCENDING ORDER --USING dbo.Sort_Dynamically_RowNumber STORED PROCEDURE EXEC dbo.Sort_Dynamically_RowNumber 'key_col', 'desc' --SORT BY modify_date column IN ASCENDING ORDER --USING dbo.Sort_Dynamically_dSQL STORED PROCEDURE EXEC dbo.Sort_Dynamically_dSQL 'modify_date', 'asc';http://scuttle.org/bookmarks.php/pass?action=add
This entry was posted on Tuesday, August 27th, 2013 at 1:18 pm and is filed under How To's, SQL, Uncategorized. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.