Passing dynamic order by in stored procedure - sql

I am creating below stored procedure.
declare #PageNum as Int
declare #PerPageResult as Int
declare #StartDate as varchar(25)
declare #EndDate as varchar(25)
declare #SortType as Varchar(50)
declare #SortDirection as Varchar(4)
set #PageNum=1
set #PerPageResult=20
set #StartDate='2008-02-08'
set #EndDate='2015-02-08'
set #SortType='RegDate'
set #SortDirection='Desc'
declare #Temp Table(RowNum int, RegDate Date, Registered int, Female int, Male int, [Join] int, Rebill int, TotalPointsEarned int, Expire int)
declare #sort varchar(50)
Insert into #Temp
Select ROW_NUMBER() over (order by #SortType+' '+#SortDirection) As RowNum, * From (
SELECT
CAST(m.registrationdate AS Date) as RegDate,
count(m.id) Registered,
count(CASE WHEN m.gender='F' then 'F' end) As Female,
count(CASE WHEN m.gender='M' then 'M' end) As Male
count(CASE WHEN p.paymenttransactiontype='N' then 'N' end) As [Join],
count(CASE WHEN p.paymenttransactiontype='R' then 'R' end) As Rebill,
count(m.tokensearned) As TotalPointsEarned,
count(CASE WHEN p.paymenttransactiontype='E' then 'E' end) As Expire
from member m
join payment p on m.id=p.id_member
join user_role u on u.member_id=m.id
where u.role_id <> 3
and CAST(m.registrationdate AS Date) > #StartDate and CAST(m.registrationdate AS Date) < #EndDate
GROUP BY CAST(m.registrationdate AS Date)
) as aa
Select * from #Temp Where RowNum>((#PageNum-1)*#PerPageResult) and RowNum<=#PerPageResult * #PageNum
Order by #SortType+' '+#SortDirection
In above when i pass the Order by clause dynamically, its not sorting the data properly but when i write column name explicitly, it works fine. Might be its taking #SortType+' '+#SortDirection as varchar rather than Date
I tried writing Order by case when (#Sort='RegDate' and #SortDirection='Desc') Then RegDate End Desc, but it didn't work
How can i pass order by dynamically here.
Edit:
#Andomar: I tried your provided solution and added one more field for Date type. And it didn't work too.
below is what i did.
create table t1 (id int, name varchar(50), dt date);
insert t1 values
(1, 'Chihiro Ogino','2009-02-08'),
(2, 'Spirit of the Kohaku River','2008-02-08'),
(3, 'Yubaba','2012-02-08');
declare #sortColumn varchar(50) = 'dt'
declare #sortOrder varchar(50) = 'ASC'
select *
from t1
order by
case
when #sortOrder <> 'ASC' then 0
when #sortColumn = 'id' then id
end ASC
, case
when #sortOrder <> 'ASC' then ''
when #sortColumn = 'name' then name
end ASC
, case
when #sortOrder <> 'ASC' then ''
when #sortColumn = 'dt' then name
end ASC
, case
when #sortOrder <> 'DESC' then 0
when #sortColumn = 'id' then id
end DESC
, case
when #sortOrder <> 'DESC' then ''
when #sortColumn = 'name' then name
end DESC
, case
when #sortOrder <> 'DESC' then ''
when #sortColumn = 'dt' then name
end DESC

You can use a complicated order by clause. That requires one case for each sort direction and each data type. With this example dataset:
create table t1 (id int, name varchar(50), created date);
insert t1 values
(1, 'Chihiro Ogino', '2012-01-01'),
(2, 'Spirit of the Kohaku River', '2012-01-03'),
(3, 'Yubaba', '2012-01-02');
You could use an order by clause like:
declare #sortColumn varchar(50) = 'created'
declare #sortOrder varchar(50) = 'DESC'
select *
from t1
order by
case
when #sortOrder <> 'ASC' then 0
when #sortColumn = 'id' then id
end ASC
, case
when #sortOrder <> 'ASC' then ''
when #sortColumn = 'name' then name
end ASC
, case
when #sortOrder <> 'ASC' then cast(null as date)
when #sortColumn = 'created' then created
end ASC
, case
when #sortOrder <> 'DESC' then 0
when #sortColumn = 'id' then id
end DESC
, case
when #sortOrder <> 'DESC' then ''
when #sortColumn = 'name' then name
end DESC
, case
when #sortOrder <> 'DESC' then cast(null as date)
when #sortColumn = 'created' then created
end DESC
Working example at SQL Fiddle.
Another option is to create the query dynamically, and run it with exec. For example:
declare #sql nvarchar(max)
set #sql = 'select * from YourTable order by ' + #sortColumn + ' ' + #sortDir
exec (#sql)

#Andomar's answer help solve a similar issue. I needed to sort on any number of 23 different columns, in any order. I ended up with the following:
create table sorting(ID int, columnName varchar(50), sort varchar(10), position int)
insert into sorting
values(1,'column1','DESC',1),
(1,'column2','ASC',2),
...
(1,'columnN','DESC',N)
Adding parameter #sort to the SP to identify the entries in sorting:
ORDER BY ISNULL(STUFF((SELECT ', ' + a.columnName + ' ' + a.sort
FROM sorting a
WHERE a.ID = #sort
ORDER BY a.position ASC
FOR XML PATH('')), 1, 2, ''),NULL)

There are two basic approaches to building dynamically orderable stored procedures:
Pass in the ORDER BY clause as a parameter to the stored procedure. In the stored procedure, build up the SQL statement in a string and then execute this statement using EXEC or sp_ExecuteSql.
-- This Method is used when your Column names are dynamic
-- We need to create a dynamic query and Execute it as shown below.
CREATE PROCEDURE getEmployees ( #OrderByClause varchar(100) ) AS
-- Create a variable #SQLStatement
DECLARE #SQLStatement varchar(255)
-- Enter the dynamic SQL statement into the
-- variable #SQLStatement
SELECT #SQLStatement = 'SELECT EmployeeID, FirstName, LastName, SSN, Salary
FROM Employees ORDER BY '+ #OrderByClause+''
-- Execute the SQL statement
EXEC(#SQLStatement)
Pass in the column to sort by and then use a CASE statement in the ORDER BY clause to order the results according to the input parameter value.
--This method is used when you column name is not dynamic
SELECT EmployeeID, FirstName, LastName, SSN, Salary
FROM Employees
ORDER BY
CASE WHEN #ColumnName='LastName' THEN LastName
WHEN #ColumnName='Salary' THEN CONVERT(varchar(50), Salary)
WHEN #ColumnName='SSN' THEN SSN
END

something like this should work :
ORDER BY
CASE WHEN #SortDirection = 'ASC' THEN #SortType END ASC,
CASE WHEN #SortDirection = 'DESC' THEN #SortType END DESC

Related

Error in Order by clause when using case statement in SQL Server

I have a stored procedure defined as below. When I execute it, I get an error and couldn't come up with a solution.
ALTER PROCEDURE [dbo].[GetShippmentList]
#shipmentNumber VARCHAR(20),
#requestType VARCHAR(1),
#shipmentNames VARCHAR(100),
#assigneeDateFrom DATETIME,
#assignedDateTo DATETIME,
#completedDateFrom DATETIME,
#completedDateto DATETIME,
#status VARCHAR(20),
#userId VARCHAR(20),
#pageNo int,
#pageSize int,
#sortField VARCHAR(20),
#sortOrder VARCHAR(4)
AS
BEGIN
SET NOCOUNT ON
IF OBJECT_ID('tempdb..##ApTemp') IS NULL
BEGIN
CREATE TABLE ##ApTemp(INST_ID VARCHAR(32),
STATUS NVARCHAR(16),
NAME NVARCHAR(64),
ASSIGNED_DATE DATETIME NULL,
COMPLETED_DATE DATETIME NULL,
USER_ID NVARCHAR(64) )
INSERT INTO ##ApTemp(INST_ID, STATUS, NAME, ASSIGNED_DATE, COMPLETED_DATE, USER_ID)
SELECT
w.INST_ID, w.STATUS, w.NAME, w.ASSIGNED_DATE,
w.COMPLETED_DATE, w.USER_ID
FROM
WestShipment.Shipmentt_Prod.dbo.WShipments w
WHERE
w.NAME IN ('T1', 'T2', 'T5', 'T51', 'T3', 'T31')
AND w.STATUS NOT IN ('Removed', 'Cancelled')
AND w.APP IN ('East', 'West')
END
AS (
SELECT w.INST_ID, w.NAME, w.ASSIGNED_DATE AS AssignedDate, w.COMPLETED_DATE AS CompletedDate,w.STATUS AS WfStatus, w.USER_ID AS User_Id,
STUFF(
(SELECT '','' + t.USER_ID
FROM ##ApTemp t
WHERE t.INST_ID = w.Inst_ID AND t.NAME = w.Name
FOR XML PATH ('')), 1, 1, '') AS Assignees
FROM ##ApTemp AS w
WHERE (w.NAME IN( #shipmentNames) OR LEN(#shipmentNames) > 4)
AND ( w.STATUS IN (#status) OR LEN(#status) > 4)
AND ((w.ASSIGNED_DATE BETWEEN #assigneeDateFrom AND #assignedDateTo) OR LEN(#assigneeDateFrom) >4 OR LEN(#assignedDateTo) > 4)
AND ((w.COMPLETED_DATE BETWEEN #completedDateFrom AND #completedDateto) OR LEN(#completedDateFrom) >4 OR LEN(#completedDateto) >4)
AND (w.User_ID LIKE #userId OR LEN(#userId) > 4 )
GROUP BY w.NST_ID, w.NAME , w.ASSIGNED_DATE, w.COMPLETED_DATE,w.STATUS, User_Id
)
INSERT INTO #tempTable(INST_ID, NAME, AssignedDate, CompletedDate, WfStatus, Assignees, ShippmentNumber , ShipmentName , RequestType )
SELECT w.INST_ID, w.NAME, w.AssignedDate, w.CompletedDate, w.WfStatus, w.Assignees, m.DocumentNumber, m.ShipmentName, m.RequestType
FROM dbo.DncMain m INNER JOIN workflows w ON m.InstanceId = w.INST_ID
WHERE (m.ShipmentNumber = #shipmentNumber OR LEN(#shipmentNumber) > 4)
AND(m.RequestType = #requestType OR #requestType NOT LIKE '0')
IF #sortOrder = 'DESC'
begin
SELECT INST_ID, NAME, AssignedDate, CompletedDate, WfStatus, Assignees, ShipmentNumber, ShipmentName FROM #tempTable
ORDER BY CASE #sortField
WHEN 'ShipmentNumber' THEN ShipmentNumber
WHEN 'TaskName' THEN NAME
WHEN 'ShipmentName' THEN ShipmentName
WHEN 'AssignedDate' THEN AssignedDate
WHEN 'CompletedDate' THEN CompletedDate
WHEN 'Assignees' THEN Assignees
WHEN 'Status' THEN WfStatus
END DESC OFFSET (#pageNo) ROWS FETCH NEXT(#pageSize) ROW ONLY
end
ELSE
begin
SELECT TOP(#pageNo) INST_ID, NAME, AssignedDate, CompletedDate, WfStatus, Assignees, ShipmentNumber, ShipmentName FROM #tempTable
ORDER BY CASE #sortField
WHEN 'TaskName' THEN NAME
WHEN 'ShipmentName' THEN ShipmentName
WHEN 'ShipmentNumber' THEN ShipmentNumber
WHEN 'AssignedDate' THEN AssignedDate
WHEN 'CompletedDate' THEN CompletedDate
WHEN 'Assignees' THEN Assignees
WHEN 'Status' THEN WfStatus
END ASC OFFSET (#pageNo) ROWS FETCH NEXT(#pageSize) ROW ONLY
end
SELECT COUNT(1) AS TotalRows FROM #tempTable
END
GO
The error I got is :
Msg 8115, Level 16, State 2, Procedure GetShipmentList, Line 60
Arithmetic overflow error converting expression to data type datetime.
The problem looks like in the order by clause. If I remove the case statement from the ORDER BY clause, it works fine.
This is an order by:
ORDER BY CASE #sortField
WHEN 'TaskName' THEN NAME
WHEN 'ShipmentName' THEN ShipmentName
WHEN 'ShipmentNumber' THEN ShipmentNumber
WHEN 'AssignedDate' THEN AssignedDate
WHEN 'CompletedDate' THEN CompletedDate
WHEN 'Assignees' THEN Assignees
WHEN 'Status' THEN WfStatus
END ASC
This is a single expression in SQL. It returns one specific type -- regardless of which WHEN clause is being executed. That causes a problem.
So, another way of writing the logic is to split this to different case statements:
ORDER BY (CASE #sortField WHEN 'TaskName' THEN NAME END) ASC,
(CASE #sortField WHEN 'ShipmentName' THEN ShipmentName END) ASC,
(CASE #sortField WHEN 'ShipmentNumber' THEN ShipmentNumber END) ASC,
(CASE #sortField WHEN 'AssignedDate' THEN AssignedDate END) ASC,
(CASE #sortField WHEN 'CompletedDate' THEN CompletedDate END) ASC,
(CASE #sortField WHEN 'Assignees' THEN Assignees END) ASC,
(CASE #sortField WHEN 'Status' THEN WfStatus END) ASC
This puts each column as a separate key, so you cannot get conflicts.
You are trying to convert a number to a datetime, which you cannot do. First, you must convert it to a string (varchar).
For example:
declare #IntegerDate int = 20151223
select cast(#IntegerDate as datetime) //this will throw an error
select cast(cast(#IntegerDate as varchar) as datetime) //This will work
Another approach is to use dynamic SQL to generate different SQL for the different choices, allowing the optimizer to choose the best plan for each.
DECLARE #ComputedSortField SYSNAME = CASE #sortField
WHEN 'ShipmentNumber' THEN N'ShipmentNumber'
WHEN 'TaskName' THEN N'NAME'
WHEN 'ShipmentName' THEN N'ShipmentName'
WHEN 'AssignedDate' THEN N'AssignedDate'
WHEN 'CompletedDate' THEN N'CompletedDate'
WHEN 'Assignees' THEN N'Assignees'
WHEN 'Status' THEN N'WfStatus'
END
DECLARE #TopClause NVARCHAR(13) = CASE #SortOrder
WHEN 'DESC' THEN N''
ELSE N'TOP(#pageNo)'
END
DECLARE #ComputedSortOrder NVARCHAR(4) = CASE #SortOrder
WHEN 'DESC' THEN N'DESC'
ELSE N'ASC'
END
DECLARE #Sql NVARCHAR(MAX) = N'SELECT ' + #TopClause + N' INST_ID, NAME, AssignedDate,
CompletedDate, WfStatus, Assignees, ShipmentNumber, ShipmentName
FROM #tempTable
ORDER BY ' + #ComputedSortField + N' ' + #ComputedSortOrder + N'
OFFSET (#pageNo) ROWS FETCH NEXT(#pageSize) ROW ONLY'
PRINT #Sql
EXECUTE sp_executesql #Statement = #Sql
, #Params = N'#pageNo int, #pageSize int'
, #PageNo = #PageNo
, #PageSize = #PageSize
Note that all the pieces being concatenated together are defined within the code. There is nothing from a parameter that is being concatenated into the string to avoid SQL injection attacks.
If #SortField does not match one of the defined sorts #ComputedSortField will be null causing #Sql to be null. You may want to define a default #ComputedSortField or make an #OrderByClause that can be set to '', removing sorting, when a proper #SortField value is passed.

SQL Case with 2 conditions [duplicate]

This question already has answers here:
T-SQL Conditional Order By
(4 answers)
Closed 8 years ago.
I have a stored procedure that will accept 2 different parameters. The first parameter will determine which column I want to sort on, the second parameter will determine whether it is ASC or DESC
Create Procedure Some_SP
#sortcolumn varchar(10)
#sortorder varchar(10)
AS
Select * from empTable
Order by
CASE #sortcolumn WHEN 'First_Name' THEN fname END,
CASE #sortcolumn WHEN 'Last_Name' THEN lname END,
CASE #sortcolumn WHEN 'ID' THEN empID END,
CASE #sortorder WHEN 'ascending' THEN ASC END,
CASE #sortorder WHEN 'descending' THEN DESC END
It is giving me syntax error. How do I fix it so that I can have 2 conditions in my CASE statement?
The following will work:
Select * from empTable
Order by
CASE WHEN #sortcolumn = 'First_Name' AND #SortOrder = 'ascending' THEN fname END ASC,
CASE WHEN #sortcolumn = 'First_Name' AND #SortOrder = 'descending' THEN fname END DESC
etc...
In order to avoid typing each of these case statements by hand, you could write a "generator" script that you use to create this (especially good if the table definition would change):
SELECT
'CASE WHEN #SortColumn = ''' + C.name + ''' AND #SortOrder = ''ascending'' THEN ' + C.name + ' END ASC,' + CHAR(13) + CHAR(10) +
'CASE WHEN #SortColumn = ''' + C.name + ''' AND #SortOrder = ''descending'' THEN ' + C.name + ' END DESC,'
FROM sys.columns C
WHERE C.object_id = object_id('[Schema].[Table]')
If you want to avoid dynamic SQL and using 2x your conditions, you can use row_number
eg:
declare #t table (string varchar(50), number int)
insert #t values ('a',9),('f',2),('c',1)
declare
#sc varchar(10) = 'number', -- or 'string', etc
#so varchar(10) = 'desc' -- or 'asc'
select *
from
(
select
*,
case #sc when 'string' then ROW_NUMBER() over (order by string)
when 'number' then ROW_NUMBER() over (order by number)
end rn
from #t
) v
order by
case #so when 'desc' then -rn else rn end
You can just copy and paste and run this. I hate dynamic SQL, don't do it.
Unfortunately you'll have to duplicate the query....but it solves your specific problem.
DECLARE
#sortcolumn varchar(10),
#sortorder varchar(10)
SET #sortcolumn = 'fname'
SET #sortorder = 'DESC'
DECLARE
#Data TABLE
(
fname nvarchar(10),
lname nvarchar(10),
empID int
)
INSERT INTO #Data VALUES ('BBB', 'BBB', 2)
INSERT INTO #Data VALUES ('AAA', 'AAA', 1)
IF #sortorder = 'DESC' BEGIN
SELECT
*
FROM
#Data
ORDER BY
CASE
WHEN #sortcolumn = 'fname' THEN fname
WHEN #sortcolumn = 'lname' THEN lname
END
DESC
END ELSE BEGIN
SELECT
*
FROM
#Data
ORDER BY
CASE
WHEN #sortcolumn = 'fname' THEN fname
WHEN #sortcolumn = 'lname' THEN lname
END
END
Modifying Jon's answer to cap the ORDER BY list at just 2 instead of 2 * #columns
SELECT *
FROM MyTable
CROSS APPLY (VALUES
('First_Name',fname),
('Last_Name' ,lname),
('Id' ,ID )
) sort(SortColumn, SortValue)
WHERE SortColumn = #SortColumn
ORDER BY
CASE #SortOrder WHEN 'ascending' THEN SortValue END ASC,
CASE #SortOrder WHEN 'descending' THEN SortValue END DESC

How to Sort datetime in ROW_NUMBER() OVER ( ORDER BY clause

Hi the below query is a prototype of a bigger complex query
The problem is that i should be able sort any column in any order (i.e. ASC and DESC) based on user input.
CREATE table #Table1(
Name varchar(10) PRIMARY key,
DOB DateTime,
Rate numeric(10,2)
)
INSERT INTO #Table1 (Name,DOB,Rate) values ('Name1','2/2/2012',10.23)
INSERT INTO #Table1 (Name,DOB,Rate) values ('Name2','3/2/2012',120.23)
INSERT INTO #Table1 (Name,DOB,Rate) values ('Name3','4/2/2012',110.23)
INSERT INTO #Table1 (Name,DOB,Rate) values ('Name4','5/2/2012',140.23)
INSERT INTO #Table1 (Name,DOB,Rate) values ('Name15','6/2/2012',130.23)
INSERT INTO #Table1 (Name,DOB,Rate) values ('Name6','2/21/2012',1120.23)
Declare #SortColumn varchar(10)
DECLARE #SortExpression varchar (10)
SET #SortColumn = 'DOB'
SET #SortExpression = 'DESC' -- Need to sort in both ASC and DESC
Select
Name,
DOB,
Rate,
ROW_NUMBER() OVER
(ORDER BY
CASE WHEN #SortColumn = 'Name' then Name
WHEN #SortColumn = 'DOB' THEN DOB
WHEN #SortColumn = 'Rate' THEN Rate
END + #SortExpression
) AS RowNumber
FROM
#Table1
Looks like you need to CAST() and CONVERT() the items in the CASE to get it to work:
Declare #SortColumn varchar(10)
DECLARE #SortExpression varchar (10)
SET #SortColumn = 'DOB'
SET #SortExpression = 'DESC' -- Need to sort in both ASC and DESC
Select
Name,
DOB,
Rate,
ROW_NUMBER() OVER
(ORDER BY
CASE WHEN #SortColumn = 'Name' then Name
WHEN #SortColumn = 'DOB' THEN convert(char(10), DOB, 120)
WHEN #SortColumn = 'Rate' THEN Cast(Rate as varchar(10))
END ASC
) AS RowNumberASC,
ROW_NUMBER() OVER
(ORDER BY
CASE WHEN #SortColumn = 'Name' then Name
WHEN #SortColumn = 'DOB' THEN convert(char(10), DOB, 120)
WHEN #SortColumn = 'Rate' THEN Cast(Rate as varchar(10))
END DESC
) AS RowNumberDESC
FROM Table1
See SQL Fiddle with Demo
As #Martin pointed out the ASC, DESC cannot be parameterized.
If you need to switch between ASC and DESC dynamically, you will have to use a dynamic statement.
SQL Fiddle here. Be aware of SQL Injection!
EXECUTE(' SELECT Name, DOB, Rate,'
+ ' ROW_NUMBER() OVER( ORDER BY ' + #SortColumn + ' ' + #SortExpression
+ ' ) AS RowNumber'
+ ' FROM Table1');
If your query is complex, consider putting it into a view and select from that view to allow compile-time checking of that part.

ORDER BY with a CASE statement for column with alias

I need a stored procedure which will allow me to return sorted results based on two input parameters: #sortColumnName and #sortDirection. I wrote the following stored procedure, but when I run it, I am getting this error: "Invalid column name 'LastPayCheckDate'."
SELECT Name, SUM(Pay), MAX(PayCheckDate) as LastPayCheckDate
FROM Employee
GROUP BY Name
ORDER BY
CASE WHEN #sortColumnName = 'LastPayCheckDate' AND #sortDirection = 'ASC'
THEN [LastPayCheckDate] END ASC,
CASE WHEN #sortColumnName = 'LastPayCheckDate' AND #sortDirection = 'DESC'
THEN [LastPayCheckDate] END DESC
What is going on? I suppose that t-sql runs the case statement before the select... Am I right? How can I work around this issue?
Thanks for the help!
Try this
ORDER BY
CASE WHEN #sortColumnName = 'LastPayCheckDate' AND #sortDirection = 'ASC'
THEN MAX(PayCheckDate) END ASC,
CASE WHEN #sortColumnName = 'LastPayCheckDate' AND #sortDirection = 'DESC'
THEN MAX(PayCheckDate) END DESC
Example
create table Test (id int, somevalue int)
insert Test values(1,1)
insert Test values(2,1)
insert Test values(3,2)
insert Test values(3,2)
insert Test values(4,2)
run this in 1 shot
declare #sortDirection char(4)
select #sortDirection = 'DESC'
select somevalue, COUNT(*)
from Test
group by somevalue
order by case when #sortDirection = 'ASC'
then COUNT(*) end asc,
case when #sortDirection = 'DESC'
then COUNT(*) end desc
select #sortDirection = 'ASC'
select somevalue, COUNT(*)
from Test
group by somevalue
order by case when #sortDirection = 'ASC'
then COUNT(*) end asc,
case when #sortDirection = 'DESC'
then COUNT(*) end desc
You need to either use the function again or use a subquery if you want to be able to refer to the column alias.
Also, I think that you need to make sure that all of your columns in the case statement get converted to the same data type.

Dynamic order by without using dynamic sql?

I have the following stored procedure which can be sorted ascending and descending on TemplateName,CreatedOn and UploadedBy. The following SP when runs doesnot sort records.if i replace 2,3,4 by columnname, i got an error message "Conversion failed when converting the nvarchar value 'Test Template' to data type int.".Please suggest how to achieve sorting.
CREATE PROCEDURE [dbo].[usp_SEL_GetRenderingTemplate]
(
#facilityID INT,
#sortOrder VARCHAR(5),
#sortExpression VARCHAR(100),
#errorCode INT OUTPUT
)
AS
BEGIN
SET NOCOUNT ON ;
BEGIN TRY
SET #sortOrder = CASE #sortOrder
WHEN 'Ascending' THEN 'ASC'
WHEN 'Descending' THEN 'DESC'
ELSE 'ASC'
END
SELECT TemplateID,
TemplateName,
CreatedOn,
( [user].LastName + ' ' + [user].FirstName ) AS UploadedBy
FROM Templates
INNER JOIN [user] ON [user].UserID = Templates.CreatedBy
WHERE facilityid = #facilityID
ORDER BY CASE WHEN #sortExpression = 'TemplateName'
AND #sortOrder = 'ASC' THEN 2
WHEN #sortExpression = 'CreatedOn'
AND #sortOrder = 'ASC' THEN 3
WHEN #sortExpression = 'UploadedBy'
AND #sortOrder = 'ASC' THEN 4
END ASC,
CASE WHEN #sortExpression = 'TemplateName'
AND #sortOrder = 'DESC' THEN 2
WHEN #sortExpression = 'CreatedOn'
AND #sortOrder = 'DESC' THEN 3
WHEN #sortExpression = 'UploadedBy'
AND #sortOrder = 'DESC' THEN 4
END DESC
SET #errorCode = 0
END TRY
BEGIN CATCH
SET #errorCode = -1
DECLARE #errorMsg AS VARCHAR(MAX)
DECLARE #utcDate AS DATETIME
SET #errorMsg = CAST(ERROR_MESSAGE() AS VARCHAR(MAX))
SET #utcDate = CAST(GETUTCDATE() AS DATETIME)
EXEC usp_INS_LogException 'usp_SEL_GetFacilityWorkTypeList',
#errorMsg, #utcDate
END CATCH
END
The dynamic ordering has to be of the same datatype. Here is an example of something that I use to case order three different datatypes - integer, date (ascending and descending), and string. This may not work for your situation, but at least you can see some techniques for casting to a common datatype.
...
ORDER BY
Case Parent.RankTypeID
When 0 Then dbo.Documents.Rank
When 1 Then Convert(int, dbo.Documents.DateStart, 112)
When 2 Then (1 - Convert(int, dbo.Documents.DateStart, 112))
When 3 Then Cast(dbo.Documents.Title as sql_variant)
End
Note:
112 is a date format of YYYYMMDD - useful for ordering.
We perform a similar sort of dynamic ordering in one of our products.
The only real different to your code is firstly, we don't use the live join.
We create a temporary table, so we can perform paging, and then apply the order.
We also use ints for ordering, cuts down on the overhead of string comparison.
It does make your SQL a bit longer, but this approach is definitely faster for the Query Optimiser. Also, and more importantly, I don't think you can mix types in Switch blocks, for ordering, so to follow your original code, you'd have to CONVERT all your data to the same time, which defeats the object :(
So you'd have
DECLARE #temp TABLE(ID int identity(1,1), TemplateID int, TemplateName nvarchar(100), CreatedOn datetime, UploadedBy nvarchar(100))
INSERT INTO #temp(TemplateID, TemplateName, CreatedOn, UploadedBy)
SELECT TemplateID,
TemplateName,
CreatedOn,
( [user].LastName + ' ' + [user].FirstName ) AS UploadedBy
FROM Templates
INNER JOIN [user] ON [user].UserID = Templates.CreatedBy
WHERE facilityid = #facilityID
Then:
IF #SortOrder = 1 --'ASC'
BEGIN
IF #sort = 2
Select *
From #Temp
Order by TemplateName ASC
ELSE IF #sort = 3
Select *
From #Temp
Order By CreatedBy ASC
-- and so on...
END
ELSE -- descending
BEGIN
-- Ad. Inf.
END
Delete
From #Temp
WHERE ID < #pageStart or ID > #pageStart + #pageSize
The following SP when runs doesnot
sort records.if i replace 2,3,4 by
columnname,
You shouldn't replace 2, 3, 4 in the ORDER BY clause by the column name. When you call the procedure just pass the column you want to sort by as the 3rd parameter.
EXEC [dbo].[usp_SEL_GetRenderingTemplate] 1,'Ascending','CreatedOn',#vErrorCode
The CASE will then evaluate the query to something like
...ORDER BY 3 DESC
which sorts the query by the 3rd column in the SELECT clause (i.e. CreatedOn)
The problem is that in CASE clauses the return values must have the same data type.
You can work around this problem by using multiple CASE statements http://www.extremeexperts.com/sql/articles/CASEinORDER.aspx
Or casting everything to the same data type.