如何在SQL Server中使用带有Order by子句的变量

时间:2016-03-14 13:03:54

标签: sql sql-server sql-server-2008 sorting

我有一个变量,其中包含如下所示的排序信息。排序信息可能会根据我将其保存在变量中的列而有所不同。

Declare @Sorting varchar(100) = 'AssetCode asc'

我正在使用此变量进行以下查询排序,但它不会根据排序详细信息对数据进行排序。

with _result as         
(        
    select        
        ROW_NUMBER() over (order by @Sorting) as RowIndex,        
        *         
    from 
        @Assets        
    where 
        (@Keyword is null or (AssetCode like @Keyword         
                              or DisplayName like @Keyword        
                              or CategoryName like @Keyword        
                              or SiteName like @Keyword        
                              or BldgName like @Keyword        
                              or SuiteName like @Keyword        
                              or Location like @Keyword  
                              or SerialVIN like @Keyword    
                              or Barcode like @Keyword))       
        )

任何人都可以告诉我如何使用此变量与查询对结果进行排序?我会非常感激的。

3 个答案:

答案 0 :(得分:3)

不使用动态SQL的替代方法:

-- order by flags, 1 = ASC, 0 = DESC, NULL = not order by this.
Declare @SortingByAssetCode bit = NULL;
Declare @SortingByDisplayName bit = 1;
Declare @SortingByCategoryName bit = NULL;
....

SELECT ...
...
ORDER BY 
  CASE WHEN SortingByAssetCode = 1 THEN AssetCode ELSE 0 END ASC,
  CASE WHEN SortingByAssetCode = 0 THEN AssetCode ELSE 0 END DESC,
  CASE WHEN SortingByDisplayName = 1 THEN DisplayName ELSE 0 END ASC,
  CASE WHEN SortingByDisplayName = 0 THEN DisplayName ELSE 0 END DESC,
  ...

您无法动态更改字段的顺序(例如先按显示名称排序,然后再按资产代码排序)。

很可能它真的很慢而且真的很难维护。

答案 1 :(得分:1)

您可以使用简单的CASE语句在没有动态SQL的情况下执行此操作。您可能希望调整变量以使用单独的ASC' DESC'变量,虽然您可以在紧要关系中解析现有变量。

SELECT
    ROW_NUMBER() OVER (ORDER BY
                           CASE WHEN @order = 'DESC' THEN
                               CASE @Sorting
                                   WHEN 'customer_id' THEN RIGHT(REPLICATE('0', 20) + CAST(customer_id AS VARCHAR(20)), 20)
                                   WHEN 'first_name' THEN first_name
                                   ... etc.
                                   ELSE NULL
                               END
                               ELSE NULL
                           END DESC,
                           CASE WHEN @order = 'DESC' THEN
                               CASE @Sorting
                                   WHEN 'customer_id' THEN RIGHT(REPLICATE('0', 20) + CAST(customer_id AS VARCHAR(20)), 20)
                                   WHEN 'first_name' THEN first_name
                                   ... etc.
                                   ELSE NULL
                               END
                               ELSE NULL
                           END ASC
) as RowIndex,
    *
FROM
    @Assets
WHERE

请注意customer_id必须如何按摩到一个字符串中,该字符串将正确排序为字符串。您需要对日期等进行相同操作,因为所有数据类型必须匹配。字符串是可以强制转换为所有数据类型的字符串(虽然从技术上讲,我应该可能使用NVARCHAR)。

答案 2 :(得分:1)

如果要传递这样的变量,则需要使用多个case语句。给定变量的结构:

row_number() over ((case when @sorting = 'AssetCode asc' then AssetCode end) asc,
                   (case when @sorting = 'AssetCode desc' then AssetCode end) desc,
                   . . .
                  )

您应该可以为您的目的添加足够的这些表达式。关键是缺少else条款。默认为NULL,因此不匹配的值都相同。我认为没有理由将asc / desc分隔为单独的变量。

另一种选择是动态SQL。动态SQL的优势在于优化器可以使用索引进行row_number()计算。