使用存储过程进行分页
Posted
技术标签:
【中文标题】使用存储过程进行分页【英文标题】:Pagination with the stored procedure 【发布时间】:2013-07-22 02:27:04 【问题描述】:我正在尝试添加分页存储过程的排序功能。
我怎样才能做到这一点,到目前为止我创建了这个。它工作正常,但是当传递@sort
参数时,它不起作用。
ALTER PROCEDURE [dbo].[sp_Mk]
@page INT,
@size INT,
@sort nvarchar(50) ,
@totalrow INT OUTPUT
AS
BEGIN
DECLARE @offset INT
DECLARE @newsize INT
IF(@page=0)
begin
SET @offset = @page;
SET @newsize = @size
end
ELSE
begin
SET @offset = @page+1;
SET @newsize = @size-1
end
-- SET NOCOUNT ON added to prevent extra result sets from
SET NOCOUNT ON;
WITH OrderedSet AS
(
SELECT *,
ROW_NUMBER() OVER (ORDER BY @sort DESC) AS 'Index'
FROM [dbo].[Mk]
)
SELECT *
FROM OrderedSet
WHERE [Index] BETWEEN @offset AND (@offset + @newsize)
SET @totalrow = (SELECT COUNT(*) FROM [dbo].[Mk])
END
【问题讨论】:
试试OFFSET FETCH
technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx
【参考方案1】:
我正在添加一个答案,因为许多其他答案都建议使用动态 SQL,这不是最佳实践。您可以使用OFFSET-FETCH
子句添加分页,该子句为您提供了从结果集中仅获取结果窗口或结果页面的选项。
注意:OFFSET-FETCH
只能与ORDER BY
子句一起使用。
例子:
SELECT First Name + ' ' + Last Name FROM Employees
ORDER BY First Name
OFFSET 10 ROWS FETCH NEXT 5 ROWS ONLY;
【讨论】:
我认为它是目前(截至 2018 年 2 月)的首选解决方案,但我应该指出,此选项仅在 MS SQL Server 版本 2012 之后可用,请参阅:sqlservergeeks.com/t-sql-paging-stored-procedure【参考方案2】:一种方法(可能不是最好的)是使用动态 SQL
CREATE PROCEDURE [sp_Mk]
@page INT,
@size INT,
@sort nvarchar(50) ,
@totalrow INT OUTPUT
AS
BEGIN
DECLARE @offset INT
DECLARE @newsize INT
DECLARE @sql NVARCHAR(MAX)
IF(@page=0)
BEGIN
SET @offset = @page
SET @newsize = @size
END
ELSE
BEGIN
SET @offset = @page*@size
SET @newsize = @size-1
END
SET NOCOUNT ON
SET @sql = '
WITH OrderedSet AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY ' + @sort + ') AS ''Index''
FROM [dbo].[Mk]
)
SELECT * FROM OrderedSet WHERE [Index] BETWEEN ' + CONVERT(NVARCHAR(12), @offset) + ' AND ' + CONVERT(NVARCHAR(12), (@offset + @newsize))
EXECUTE (@sql)
SET @totalrow = (SELECT COUNT(*) FROM [Mk])
END
这里是SQLFiddle演示
【讨论】:
我能问你最好的最佳解决方案是什么 更好的解决方案是使用 OFFSET-FETCH 子句添加分页。 动态 SQL 是魔鬼。如果有任何可行的替代解决方案,则绝不应使用它。【参考方案3】:假设@sort
是column name
。试试这样
WITH OrderedSet AS
(
SELECT *,
ROW_NUMBER() OVER (ORDER BY (CASE @sort WHEN 'column_name'
THEN column_name END ) DESC)
AS 'Index'
FROM [dbo].[Mk]
)
而不是提供@sort 变量put column name based on @sort
。希望这会奏效。
【讨论】:
然后呢?根据你在做什么排序 desc? 您需要按列排序吗?You are passing the name of the column in @sort parameter
。我说的对吗?
你不能直接将它(@sort)转换为列。所以你必须像上面一样使用case statement
,或者你需要使用dynamic sql
。因此,后一个严重影响您的表现,我建议第一个。
当我按照你所说的那样做时出现此错误,列名“column_name”无效。
让我们continue this discussion in chat【参考方案4】:
createprocedure [dbo].[Procedurename]
@Id bigint,
@PageNumber int,
@PageSize int,
@Keyword nvarchar(100)
AS
Begin
set NoCount on;
IF(@PageNumber <=0)
BEGIN
SET @PageNumber = 1;
END
IF(@PageSize<=0)
BEGIN
SET @PageSize = 2147483647;
END
DECLARE @SkipRows int = (@PageNumber - 1) * @PageSize;
select * from tablename
where ('condition')
and (@Keyword is null or Name like '%'+ @Keyword + '%' or Description like '%'+@Keyword+'%')
order by Id asc
OFFSET @SkipRows ROWS
FETCH NEXT @PageSize ROWS ONLY
return
End
【讨论】:
【参考方案5】:尝试使用动态 SQL 来解决此问题。
ALTER PROCEDURE [dbo].[sp_Mk]
@page INT,
@size INT,
@sort nvarchar(50) ,
@totalrow INT OUTPUT
AS
BEGIN
DECLARE @SQL nvarchar(4000)
DECLARE @Params varchar(200)
SET @Params = N'@page int, @size int, @sort nvarchar(50), @totalrow int OUTPUT'
SET @SQL = '
DECLARE @offset INT
DECLARE @newsize INT
IF(@page=0)
begin
SET @offset = @page;
SET @newsize = @size
end
ELSE
begin
SET @offset = @page+1;
SET @newsize = @size-1
end
-- SET NOCOUNT ON added to prevent extra result sets from
SET NOCOUNT ON;
WITH OrderedSet AS
(
SELECT *,
ROW_NUMBER() OVER (ORDER BY @sort DESC) AS ''Index''
FROM [dbo].[Mk]
)
SELECT *
FROM OrderedSet
WHERE [Index] BETWEEN @offset AND (@offset + @newsize)
SET @totalrow = (SELECT COUNT(*) FROM [dbo].[Mk])'
EXEC sp_executesql @SQL, @Params, @page = @page, @size = @size, @sort = @sort, @totalrow = @totalrow
END
【讨论】:
【参考方案6】:试试这个:
CREATE PROCEDURE dbo.proc_Paging_CTE_Dynamic
(
@Page int,
@RecsPerPage int,
@queryTxt varchar(MAX),
@orderBy varchar(MAX)
)
AS
-- The number of rows affected by the different commands
-- does not interest the application, so turn NOCOUNT ON
SET NOCOUNT ON
DECLARE @sql NVARCHAR(MAX)
SET @sql = '
DECLARE @Page int, @RecsPerPage int
SET @Page = ' + CAST(@Page as varchar) + '
SET @RecsPerPage = ' + CAST(@RecsPerPage as varchar) + '
-- Determine the first record and last record
DECLARE @FirstRec int, @LastRec int
SELECT @FirstRec = (@Page - 1) * @RecsPerPage
SELECT @LastRec = (@Page * @RecsPerPage + 1);
WITH TempResult as
(
SELECT ROW_NUMBER() OVER(ORDER BY ' + @orderBy + ') as RowNum,
'
+
@queryTxt
+
'
)
SELECT top (@LastRec-1) *
FROM TempResult
WHERE RowNum > @FirstRec
AND RowNum < @LastRec
'
EXECUTE (@sql)
-- Turn NOCOUNT back OFF
SET NOCOUNT OFF
GO
这样:
exec dbo.proc_Paging_CTE_Dynamic 126,
15,
'SUBSCRIBER.Number, SERVICE_MEMBER.AllowedDays, SERVICE_MEMBER.AllowedUntilTime, SERVICE_MEMBER.AllowedFromTime, SERVICE_MEMBER.Capacity,
SERVICE.Name
FROM SUBSCRIBER INNER JOIN
SERVICE_MEMBER ON SUBSCRIBER.Number = SERVICE_MEMBER.Subscriber_Number INNER JOIN
SERVICE ON SERVICE_MEMBER.Service_Id = SERVICE.Id',
'Number, Service_Id'
【讨论】:
【参考方案7】:我找到了这个链接,它工作得很好。不使用字符串/动态 sql。 相反,它使用 CASE 语句
SELECT ROW_NUMBER() OVER (ORDER BY
CASE WHEN (@lSortCol = ‘ContactID’ AND @SortOrder=‘ASC’)
THEN ContactID
END ASC,
http://www.codeproject.com/Articles/590341/Stored-Procedure-with-Sorting-Paging-and-Filtering
【讨论】:
【参考方案8】:最好的选择是使用 CTE,这将有更少的开销和可行的选择 下面是一个有用的示例, 这里我们可以使用 ROW_NUMBER() 函数只获取相关的行:
CREATE PROCEDURE dbo.uspItemsPaging
(
@Page int,
@RecsPerPage int
)
AS
-- The number of rows affected by the different commands
-- does not interest the application, so turn NOCOUNT ON
SET NOCOUNT ON
-- Determine the first record and last record
DECLARE @FirstRec int, @LastRec int
SELECT @FirstRec = (IIF ( @Page > 0 , @Page, 1 ) - 1) * @RecsPerPage - 1) * @RecsPerPage
SELECT @LastRec = (@Page * @RecsPerPage + 1);
WITH TempResult as
(
SELECT ROW_NUMBER() OVER(ORDER BY Items.ID DESC) as RowNum,
Items.*
From dbo.Items
)
SELECT top (@LastRec-1) *
FROM TempResult
WHERE RowNum > @FirstRec
AND RowNum < @LastRec
-- Turn NOCOUNT back OFF
SET NOCOUNT OFF
【讨论】:
【参考方案9】:@qtype varchar(50) = null,
@page int = 0,
@limit int = 0
SELECT * FROM [dbo].[post_image_tbl] WHERE u_id IN(SELECT f_id FROM [dbo].[followers_tbl] WHERE u_id = u_id) and
@limit BETWEEN ( @page - 1 ) * @limit + 1 AND @page * @limit
ORDER BY id DESC
【讨论】:
以上是关于使用存储过程进行分页的主要内容,如果未能解决你的问题,请参考以下文章