我传递了两个参数:
@Column和@Direction,它们都是nvarchar(50)
我想根据参数中的值更改select查询的顺序。
例如,
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
我的桌子叫做汽车。
它有三列: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
答案 0 :(得分: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
- 我不是100%确定优化器是否将其简化为冗余但是它应该崩溃单个排序运算符(需要时 - 有时此查询可以根据用于满足查询的索引产生固有排序)。
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;
当然这可能会引入其他问题(查询其余部分的可维护性,计划缓存膨胀......)
答案 1 :(得分: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's answer中所示,另一个CASE表达式用于还原如果-1
为@Direction
,则将排名乘以'DESC'
。生成的排名列可以在主查询的ORDER BY
子句中使用,无需任何调整。