1

我传递了两个参数:

@Column 和 @Direction,它们都是 nvarchar(50)

我想从参数内的值更改选择查询的顺序。

例如,

if @Column = Name and @Direction = 'Desc' then order by Name desc
if @Column = Name and @Direction = 'Asc'  then order by Name asc
if @Column = Type and @Direction = 'Desc' then order by Type desc
if @Column = Type and @Direction = 'Asc'  then order by Type asc

我的桌子叫做 Cars。

它有三列:CarId、Name、Type

我试图这样做,但它没有返回正确的结果(好像 order by 被忽略了)

select * from Cars
order by        
case 
when @SortColumn = 'Type' and @SortDir = 'Desc' then 1
when @SortColumn = 'Type' and @SortDir = 'Desc' then 1
when @SortColumn = 'Name' and @SortDir = 'Asc'  then 3
when @SortColumn = 'Name' and @SortDir = 'Asc'  then 3, end asc
4

2 回答 2

1

CASE是产生单个值的表达式。它不能像您在其他语言中那样用于控制流,或者您可以尝试使用IF. 您也不能IF在查询中使用。

以下分别处理每种情况。如果条件不匹配,则该表达式的结果为 NULL,在任何排序中都将被忽略。所以这些子句的顺序无关紧要,因为只有所有条件都为真的那些才会被观察到:

ORDER BY 
  CASE WHEN @SortColumn = 'Type' AND @SortDir = 'DESC' THEN Type END DESC,
  CASE WHEN @SortColumn = 'Name' AND @SortDir = 'DESC' THEN Name END DESC,
  CASE WHEN @SortColumn = 'Type' AND @SortDir = 'ASC'  THEN Type END,
  CASE WHEN @SortColumn = 'Name' AND @SortDir = 'ASC'  THEN Name END;

这些可能可以组合起来,但我不知道数据类型,所以这可能是最安全的。如果数据类型相同,则:

ORDER BY 
  CASE WHEN @SortDir = 'DESC' THEN 
    CASE WHEN @SortColumn = 'Type' THEN Type ELSE Name END 
  END DESC,
  CASE WHEN @SortDir = 'ASC' THEN
    CASE WHEN @SortColumn = 'Type' THEN Type ELSE Name END
  END;

您无法进一步崩溃,因为您无法在一个表达式中进行条件ASC与比较。DESC但是您可以通过其他方式进行简化,例如以下查询将产生与上述相同的结果,即使在某些情况下 order by 将尝试执行(例如)ORDER BY Type DESC, Type DESC-我不确定优化器是否将其简化为冗余但它应该折叠为单个排序运算符(需要时 - 有时此查询可能会根据用于满足查询的索引产生固有的排序)。

ORDER BY 
  CASE WHEN @SortColumn = 'Type' AND @SortDir = 'DESC' THEN Type END DESC,
  CASE WHEN @SortColumn = 'Name' AND @SortDir = 'DESC' THEN Name END DESC,
  CASE WHEN @SortColumn = 'Type' THEN Type END,
  CASE WHEN @SortColumn = 'Name' THEN Name END;

...或者...

ORDER BY 
  CASE WHEN @SortDir = 'DESC' THEN 
    CASE WHEN @SortColumn = 'Type' THEN Type ELSE Name END 
  END DESC,
  CASE WHEN @SortColumn = 'Type' THEN Type ELSE Name END;

您还可以考虑动态 SQL,因为如果这变得更复杂,这里有很多维护。

DECLARE @sql NVARCHAR(MAX);
SET @sql = N'SELECT ... ORDER BY ' + @SortColumn + ' ' + @SortDir;
PRINT @sql;
-- EXEC sp_executesql @sql;

当然这可能会引入其他问题(其余查询的可维护性,计划缓存膨胀......)

于 2012-07-03T18:00:06.920 回答
1

您可以尝试这种方法:

WITH ranked AS (
  SELECT
    ...
    rnk = ROW_NUMBER() OVER (
      ORDER BY
        CASE @SortColumn
          WHEN 'Type' THEN Type
          WHEN 'Name' THEN Name
        END
    ) * CASE @Direction WHEN 'DESC' THEN -1 ELSE 1 END
  FROM ...
)
SELECT
  ...
FROM ranked
ORDER BY rnk

ROW_NUMBER()函数在参数指定的列上产生排名,@SortColumn使用 CASE 表达式解析名称,就像在@Aaron Bertrand 的答案中一样,另一个 CASE 表达式用于通过将排名乘以-1if @Directionis来恢复顺序'DESC'。生成的排名列可以在主查询的ORDER BY子句中使用,无需任何调整。

于 2012-07-03T21:35:14.367 回答