T-SQL 条件排序依据 [英] T-SQL Conditional Order By

查看:60
本文介绍了T-SQL 条件排序依据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个存储过程,该过程返回一个对象列表,其中包含用户选择的排序顺序和排序方向,并作为 sql 参数传入.

I am trying to write a stored procedure that returns a list of object with the sort order and sort direction selected by the user and passed in as sql parameters.

假设我有一个包含以下列的产品表:product_id(int)、name(varchar)、value(int)、created_date(datetime)和参数@sortDir 和@sortOrder

Lets say I have a table of products with the following columns: product_id(int), name(varchar), value(int), created_date(datetime) and parameters @sortDir and @sortOrder

我想做类似的事情

select *
from Product
  if (@sortOrder = 'name' and @sortDir = 'asc') 
  then order by name asc
  if (@sortOrder = 'created_date' and @sortDir = 'asc') 
  then order by created_date asc
  if (@sortOrder = 'name' and @sortDir = 'desc') 
  then order by name desc
  if (@sortOrder = 'created_date' and @sortDir = 'desc') 
  then order by created_date desc

我尝试用 case 语句来做,但由于数据类型不同,所以遇到了问题.有人有什么建议吗?

I tried do it with case statements but was having problems since the data types were different. Anyone got any suggestions?

推荐答案

CASE 是一个返回值的表达式.它不是用于控制流,如 IF.并且您不能在查询中使用 IF.

CASE is an expression that returns a value. It is not for control-of-flow, like IF. And you can't use IF within a query.

不幸的是,CASE 表达式有一些限制,这使得做你想做的事情很麻烦.例如,CASE 表达式中的所有分支必须返回相同的类型,或者可以隐式转换为相同的类型.我不会用字符串和日期来尝试.您也不能使用 CASE 来指定排序方向.

Unfortunately, there are some limitations with CASE expressions that make it cumbersome to do what you want. For example, all of the branches in a CASE expression must return the same type, or be implicitly convertible to the same type. I wouldn't try that with strings and dates. You also can't use CASE to specify sort direction.

SELECT column_list_please
FROM dbo.Product -- dbo prefix please
ORDER BY 
  CASE WHEN @sortDir = 'asc' AND @sortOrder = 'name' THEN name END,
  CASE WHEN @sortDir = 'asc' AND @sortOrder = 'created_date' THEN created_date END,
  CASE WHEN @sortDir = 'desc' AND @sortOrder = 'name' THEN name END DESC,
  CASE WHEN @sortDir = 'desc' AND @sortOrder = 'created_date' THEN created_date END DESC;

一个可以说更简单的解决方案(尤其是在这变得更复杂的情况下)是使用动态 SQL.要阻止 SQL 注入,您可以测试这些值:

An arguably easier solution (especially if this gets more complex) is to use dynamic SQL. To thwart SQL injection you can test the values:

IF @sortDir NOT IN ('asc', 'desc')
  OR @sortOrder NOT IN ('name', 'created_date')
BEGIN
  RAISERROR('Invalid params', 11, 1);
  RETURN;
END

DECLARE @sql NVARCHAR(MAX) = N'SELECT column_list_please
  FROM dbo.Product ORDER BY ' + @sortOrder + ' ' + @sortDir;

EXEC sp_executesql @sql;

动态 SQL 的另一个优点,尽管散布着所有关于它的恐惧:您可以获得每个排序变体的最佳计划,而不是一个将优化您碰巧使用的任何排序变体的单一计划第一的.在我最近进行的一次性能比较中,它也普遍表现最好:

Another plus for dynamic SQL, in spite of all the fear-mongering that is spread about it: you can get the best plan for each sort variation, instead of one single plan that will optimize to whatever sort variation you happened to use first. It also performed best universally in a recent performance comparison I ran:

http://sqlperformance.com/conditional-order-by

这篇关于T-SQL 条件排序依据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆