动态ORDER BY
可以是简单的也可以是复杂的,这取决于所涉及的数据类型。如果一切都是 aDATETIME
那么你可以说:
;WITH ... ( , RowNum = ROW_NUMBER() OVER (ORDER BY
CASE WHEN @OrderType = 'ASC' THEN
CASE WHEN @OrderBy = 'LastModified' THEN LastModified
WHEN @OrderBy = 'DateCreated' THEN DateCreated
END
END,
CASE WHEN @OrderType = 'DESC' THEN
CASE WHEN @OrderBy = 'LastModified' THEN LastModified
WHEN @OrderBy = 'DateCreated' THEN DateCreated
END
END DESC) FROM ...
)
SELECT ... ORDER BY RowNum;
如果您有混合数据类型,它会变得更加复杂。由于CASE
返回一个表达式并且数据类型都必须兼容,因此每种数据类型都需要一个不同的分支。
除了复杂性之外,这不太可能为所有可能的组合产生一个好的计划。所以我宁愿做的是使用动态SQL。
DECLARE @sql NVARCHAR(MAX) = N';WITH ... ( , RowNum = ROW_NUMBER() OVER (ORDER BY '
+ @OrderBy + ' ' + @OrderType + ') FROM ... ) SELECT ...
WHERE RowNum BETWEEN @s AND @e
ORDER BY RowNum;';
EXEC sp_executesql @sql, N'@s INT, @e INT', @StartOfRange, @EndOfRange;
现在这让您对 SQL 注入持开放态度,因此您应该首先验证 @OrderBy 和 @OrderType 参数是否包含您期望的值(您可以检查前者sys.columns
以使您的代码向前兼容,并检查后者是“ASC”还是'DESC')。
还有计划缓存膨胀的问题。如果您使用的是 SQL Server 2008 或更高版本,请打开“针对临时工作负载进行优化”设置。这可以防止此查询的任何变体的计划在被使用两次之前被完全缓存。