SQL 存储过程将参数传递到“order by”

问题描述 投票:0回答:5

使用 Microsoft SQL 服务器管理器 2008。

创建一个存储过程,“最终”选择 Pareto 列表中的前 10 个。但我也想再次运行此程序以找到最后 10 个。

现在,我不是再次复制查询,而是尝试查看是否有一种方法可以将参数传递到查询中,从而将顺序从 asc 更改为 desc。

有什么方法可以让我免于复制代码吗?

CREATE PROCEDURE [dbo].[TopVRM]
@orderby varchar(255)
AS
SELECT Peroid1.Pareto FROM dbo.Peroid1
GROUP by Pareto ORDER by Pareto @orderby
sql stored-procedures sql-order-by
5个回答
13
投票

只是有点傻:

CREATE PROCEDURE [dbo].[TopVRM]
@orderby varchar(255)
AS
SELECT Peroid1.Pareto FROM dbo.Peroid1
GROUP by Pareto
ORDER by CASE WHEN @orderby='ASC' THEN Pareto END,
         CASE WHEN @orderby='DESC' THEN Pareto END DESC

您完全不需要将第二个排序条件放在CASE表达式中(*),如果

Pareto
是数字,您可能决定只做
CASE WHEN @orderby='ASC' THEN 1 ELSE -1 END * Pareto

(*) 仅当第一个排序条件认为两行相等时,第二个排序条件才有效。这是当两行具有相同的

Pareto

值时(因此反向排序也会认为它们相等),或者因为第一个 CASE 表达式返回

NULL
s (所以
@orderby
不是
'ASC'
,所以我们要执行
DESC
排序。

您可能还想考虑一次性检索两个结果集,而不是进行两次调用:

CREATE PROCEDURE [dbo].[TopVRM] @orderby varchar(255) AS SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY Pareto) as rn1, ROW_NUMBER() OVER (ORDER BY Pareto DESC) as rn2 FROM ( SELECT Peroid1.Pareto FROM dbo.Peroid1 GROUP by Pareto ) t ) t2 WHERE rn1 between 1 and 10 or rn2 between 1 and 10 ORDER BY rn1

这将为您提供前 10 名和后 10 名,按从上到下的顺序。但如果总共少于 20 个结果,您将不会获得重复项,这与您当前的计划不同。


2
投票

对几个候选解决方案(其中一些在此线程中发布)进行了一些性能测试后,我们意识到

您必须非常小心

实施:您的 SP 性能可能会受到巨大影响,特别是当您将其与 分页结合使用时 问题。 我们发现的最佳解决方案是保存原始结果,即。只需在

时态表

(示例中为#RawResult)中应用过滤器,然后添加用于分页的

ORDER BY
OFFSET
子句。也许这不是最漂亮的解决方案(因为您被迫为要排序的每一列复制并粘贴一个子句两次),但我们无法找到其他在性能方面更好的解决方案。
就这样:

CREATE PROCEDURE [dbo].[MySP] -- Here goes your procedure arguments to filter results @Page INT = 1, -- Resulting page for pagination, starting in 1 @Limit INT = 100, -- Result page size @OrderBy NVARCHAR(MAX) = NULL, -- OrderBy column @OrderByAsc BIT = 1 -- OrderBy direction (ASC/DESC) AS -- Here goes your SP logic (if any) SELECT * -- Here goes your resulting columns INTO #RawResult FROM ... -- Here goes your query data source([FROM], [WHERE], [GROUP BY], etc) -- NO [ORDER BY] / [TOP] / [FETCH HERE]!!!! --From here, ORDER BY columns must be copy&pasted twice: ASC and DESC orders for each colum IF (@OrderByAsc = 1 AND @OrderBy = 'Column1') SELECT * FROM #RawResult ORDER BY Column1 ASC OFFSET @Limit * (@Page - 1) ROWS FETCH NEXT @Limit ROWS ONLY ELSE IF (@OrderByAsc = 0 AND @OrderBy = 'Column1') SELECT * FROM #RawResult ORDER BY Column1 DESC OFFSET @Limit * (@Page - 1) ROWS FETCH NEXT @Limit ROWS ONLY ELSE IF (@OrderByAsc = 1 AND @OrderBy = 'Column2') SELECT * FROM #RawResult ORDER BY Column2 ASC OFFSET @Limit * (@Page - 1) ROWS FETCH NEXT @Limit ROWS ONLY ELSE IF (@OrderByAsc = 0 AND @OrderBy = 'Column2') SELECT * FROM #RawResult ORDER BY Column2 DESC OFFSET @Limit * (@Page - 1) ROWS FETCH NEXT @Limit ROWS ONLY ELSE ... ELSE --Default order, first column ASC SELECT * FROM #RawResult ORDER BY 1 ASC OFFSET @Limit * (@Page - 1) ROWS FETCH NEXT @Limit ROWS ONLY



1
投票

CREATE PROCEDURE [dbo].[TopVRM] (@orderby varchar(255) AS IF @orderby='asc' SELECT Peroid1.Pareto FROM dbo.Peroid1 GROUP by Pareto ORDER by Pareto asc ELSE SELECT Peroid1.Pareto FROM dbo.Peroid1 GROUP by Pareto ORDER by Pareto desc



0
投票
这给你更多选择

CREATE PROCEDURE [dbo].[TopVRM] @orderby varchar(255) = 'Pareto asc' DECLARE @SendIt NVARCHAR(MAX) AS BEGIN SET @SendIt = 'SELECT Peroid1.Pareto FROM dbo.Peroid1 GROUP by Pareto ORDER by '+ @orderby EXEC sp_executesql @SendIt END GO EXEC dbo.TopVRM 'Pareto DESC' GO



0
投票
排序

© www.soinside.com 2019 - 2024. All rights reserved.