7

我正在尝试添加分页存储过程的排序功能。

我怎么能做到这一点,到目前为止我创建了这个。它工作正常,但是当传递@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
4

9 回答 9

13

我正在添加一个答案,因为许多其他答案都建议使用动态 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;
于 2017-03-29T15:35:52.410 回答
7

一种方法(可能不是最好的)是使用动态 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演示

于 2013-07-23T07:04:49.727 回答
4

假设@sortcolumn 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。希望这会奏效。

于 2013-07-23T06:45:41.097 回答
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
于 2019-07-30T13:11:38.370 回答
2

尝试使用动态 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
于 2013-07-23T09:29:28.230 回答
1

尝试使用这个:

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'
于 2015-07-15T19:29:11.713 回答
0

我找到了这个链接,它工作得很好。不使用字符串/动态 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

于 2016-03-05T10:17:02.390 回答
0
@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
于 2018-04-05T05:42:39.343 回答
0

最好的选择是使用 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
于 2017-12-24T18:15:22.733 回答