【问题标题】: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

【问题讨论】:

标签: sql sql-server tsql stored-procedures


【解决方案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;

【讨论】:

【解决方案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】:

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

【讨论】:

  • 然后呢?根据你在做什么排序 desc?
  • 您需要按列排序吗? You are passing the name of the column in @sort parameter。我说的对吗?
  • 你不能直接将它(@sort)转换为列。所以你必须像上面一样使用case statement,或者你需要使用dynamic sql。因此,后一个严重影响您的表现,我建议第一个。
  • 当我按照你所说的那样做时出现此错误,列名“column_name”无效。
【解决方案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
            

            【讨论】:

              猜你喜欢
              • 2015-11-18
              • 2012-09-10
              • 2011-03-25
              • 1970-01-01
              • 2021-05-19
              • 1970-01-01
              • 2019-02-10
              • 1970-01-01
              • 2010-11-16
              相关资源
              最近更新 更多