SQL Server中多列的动态排序

时间:2017-02-17 19:14:31

标签: stored-procedures sql-server-2012 sql-order-by

我使用的是SQL Server 2012.我有一个名为“Table1”的示例表,其中有七列。

        CREATE TABLE TABLE1 
            (
                Field1 INT , 
                Field2 INT , 
                Field3 INT , 
                Field4 INT , 
                Field5 INT , 
                Field6 INT , 
                Field7 INT 
            )
            GO

        INSERT INTO TABLE1 VALUES (1,2,9,5,1,5,85)
        INSERT INTO TABLE1 VALUES (2,6,8,4,1,4,45)
        INSERT INTO TABLE1 VALUES (3,5,7,3,5,6,1)
        INSERT INTO TABLE1 VALUES (4,4,6,1,51,4,1)
        INSERT INTO TABLE1 VALUES (5,5,5,4,7,2,7)
        INSERT INTO TABLE1 VALUES (6,5,4,6,4,7,8)
        INSERT INTO TABLE1 VALUES (7,12,5,3,2,5,3)
        INSERT INTO TABLE1 VALUES (8,1,6,5,9,5,1)
        INSERT INTO TABLE1 VALUES (9,1,13,2,1,7,3)
        INSERT INTO TABLE1 VALUES (10,6,9,3,6,2,6)
        INSERT INTO TABLE1 VALUES (11,2,1,2,8,7,7)
        INSERT INTO TABLE1 VALUES (12,7,6,1,3,3,2)
        INSERT INTO TABLE1 VALUES (13,7,2,6,4,7,1)
        GO

我创建了以下存储过程,此SP能够按列查询所请求的订单来查询数据。     我可以通过(ASC或Desc)查询我的表中每个单列和顺序的可能性。

    CREATE Procedure ProceName
    (
        @OrderByField INT = 1,
        @OrderDirection INT = 0 -- 0 = Asc , 1 = Desc
    )  
    As  
    Begin  
        SELECT
                *  
        FROM Table1
        ORDER BY
                CASE WHEN @OrderDirection=0 AND @OrderByField=1 THEN Field1 END ASC,
                CASE WHEN @OrderDirection=0 AND @OrderByField=2 THEN Field2 END ASC,
                CASE WHEN @OrderDirection=0 AND @OrderByField=3 THEN Field3 END ASC,
                CASE WHEN @OrderDirection=0 AND @OrderByField=4 THEN Field4 END ASC,
                CASE WHEN @OrderDirection=0 AND @OrderByField=5 THEN Field5 END ASC,
                CASE WHEN @OrderDirection=0 AND @OrderByField=6 THEN Field6 END ASC,
                CASE WHEN @OrderDirection=0 AND @OrderByField=7 THEN Field7 END ASC,

                CASE WHEN @OrderDirection=1 AND @OrderByField=1 THEN Field1 END DESC,
                CASE WHEN @OrderDirection=1 AND @OrderByField=2 THEN Field2 END DESC,
                CASE WHEN @OrderDirection=1 AND @OrderByField=3 THEN Field3 END DESC,
                CASE WHEN @OrderDirection=1 AND @OrderByField=4 THEN Field4 END DESC,
                CASE WHEN @OrderDirection=1 AND @OrderByField=5 THEN Field5 END DESC,
                CASE WHEN @OrderDirection=1 AND @OrderByField=6 THEN Field6 END DESC,
                CASE WHEN @OrderDirection=1 AND @OrderByField=7 THEN Field7 END DESC        End  
    GO



EXECUTE ProceName  @OrderByField=1, @OrderDirection=0
EXECUTE ProceName  @OrderByField=6, @OrderDirection=1

现在我需要更改此sp以按系列列的顺序接受多列。它们可以按名称或按列顺序传递。         在这种情况下,我应该能够像下面的命令一样执行我的SP:

    EXECUTE ProceName  @OrderByField='6,7,2', @OrderDirection='0,1,1'

如何在不使用sp_executesql(动态查询)的情况下实现此gool

2 个答案:

答案 0 :(得分:0)

嗯,除非你试图为每一列选择asc和desc,否则你的上升和下降在你的情况下并不重要。这是使用最后一列。

DECLARE @OrderByField VARCHAR(64) = '1,3,7'

DECLARE @DynamicColumns VARCHAR(256) = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@OrderByField,1,'FIELD1'),2,'FIELD2'),3,'FIELD3'),4,'FIELD4'),5,'FIELD5'),6,'FIELD6'),7,'FIELD7')

DECLARE @OrderDirection INT = 1
DECLARE @order varchar(4)
SET @order = CASE WHEN @OrderDirection = 1 THEN 'DESC' ELSE 'ASC' END

--uncomment this line of code to add the sort to every column which only matters for DESC since ASC is default
--SET @DynamicColumns = REPLACE(@DynamicColumns,',', ' ' + @order + ',')

DECLARE @sql VARCHAR(MAX) = (
        'SELECT
                *  
        FROM Table1
        ORDER BY ' + @DynamicColumns + ' ' + @order)

SELECT @sql

EXEC(@sql)

答案 1 :(得分:0)

 CREATE Procedure ProceName
    (
        @OrderByField VARCHAR(100),
        @OrderDirection VARCHAR(100),

    )  
    As  
    Begin  

    Declare @SQL VARCHAR(MAX)

    if OBJECT_ID('Example1') is not null
    begin
    drop table Example
    end

    if OBJECT_ID('Example2') is not null
    begin
    drop table Example2
    end

    Create table Example1
    (
    id int identity(1,1),
    Field varchar(20)
    )

    Create table Example2
    (
    id int identity(1,1),
    OrderNumber varchar(10)
    )

    --iterate each element for both @OrderByField and @OrderDirection
    Declare @separator char(1)=','
    Declare @position int = 0
    Declare @name varchar(20)
    Set @OrderByField = @OrderByField + @separator 
---------------------------------------------------------------------------
         /*iterate each for @OrderByField */
---------------------------------------------------------------------------

    While CHARINDEX (@separator,@OrderByField,@position) != 0 
    BEGIN

    SET @name = SUBSTRING (@OrderByField,@position,CHARINDEX (@separator,@OrderByField,@position)-@position)

    SET @SQL = 'Insert into Example1([Field]) Values(' + char(39) + @name + char(39) + ')'
    EXEC(@SQL)

    SET @position = CHARINDEX(@separator,@OrderByField,@position)+1

    END


---------------------------------------------------------------------------
         /*iterate each for @OrderDirection */
---------------------------------------------------------------------------

    SET @position = 0 --do not forget to reset the position number

    Set @OrderDirection = @OrderDirection + @separator

    While CHARINDEX (@separator,@OrderDirection,@position) != 0 
    BEGIN

    SET @name = SUBSTRING (@OrderDirection,@position,CHARINDEX (@separator,@OrderDirection,@position)-@position)

    SET @SQL = 'Insert into Example2([OrderNumber]) Values(' + char(39) + @name + char(39)+ ')'
    EXEC(@SQL)

    SET @position = CHARINDEX(@separator,@OrderDirection,@position)+1

    END




Set @name = '' --reset the @name for the use of Cursor
declare @NewName varchar(500) =''


Declare row_cursor CURSOR
FOR
select 'Field'+a.Field + ' '+ case when b.OrderNumber = 0 then 'ASC' else 'DESC' end +',' as command
from Example1 as a 
inner join Example2 as b
on b.id = a.id


OPEN row_cursor
FETCH NEXT FROM row_cursor into @name

WHILE (@@FETCH_STATUS =0)
begin
Set @NewName = @NewName + @name

FETCH NEXT FROM row_cursor into @name
end
close row_cursor
deallocate row_cursor

SET @NewName = REVERSE(STUFF(REVERSE(@NewName),1,1,''))


SET @SQL = 'Select * From Table1 Order by ' + @NewName

--Print(@SQL)
EXEC (@SQL)

END