使用 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
只是有点傻:
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 个结果,您将不会获得重复项,这与您当前的计划不同。
对几个候选解决方案(其中一些在此线程中发布)进行了一些性能测试后,我们意识到
您必须非常小心实施:您的 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
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
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