Passing dynamic order by in stored procedure

陌路散爱 提交于 2020-01-09 19:30:51

问题


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

回答1:


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)



回答2:


@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)



回答3:


There are two basic approaches to building dynamically orderable stored procedures:

  1. 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)
    
  2. 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
    



回答4:


something like this should work :

ORDER BY
  CASE WHEN @SortDirection = 'ASC'  THEN @SortType END ASC,
  CASE WHEN @SortDirection = 'DESC' THEN @SortType END DESC


来源:https://stackoverflow.com/questions/15085149/passing-dynamic-order-by-in-stored-procedure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!