-2

如何将参数传递给此过程以支持不同@OrderBy@OrderType排序选项?我想要完成的,但不是有效的语法:

WITH results AS
(
    SELECT id, title, LastModified, 
      ROW_NUMBER() over (ORDER BY @OrderBy @OrderType) RowNum
----------------------------------^^^^^^^^^^^^^^^^^^^
    FROM dbo.EmploymentOpportunities
    where CompanyId = 148

)
SELECT id, title, LastModified, (select count(*) from results) totalcount
FROM results
where RowNum between 1 and 9
ORDER BY RowNum 
OPTION (Maxdop 8)
4

1 回答 1

4

动态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 或更高版本,请打开“针对临时工作负载进行优化”设置。这可以防止此查询的任何变体的计划在被使用两次之前被完全缓存。

于 2013-10-24T14:58:08.340 回答