2013-07-23 93 views
1

我想添加我的分頁存儲過程的排序功能。分頁與存儲過程

我該如何做到這一點,到目前爲止我創建了這一個。它工作正常,但通過@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 
+1

嘗試'OFFSET FETCH' https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx – Jaider

回答

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+1 
     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演示

+0

我可以問你什麼是最佳最佳解決方案可能是 – sakir

+0

更好的解決方案是使用OFFSET-FETCH子句添加分頁。 – Tarzan

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變量放column name based on @sort。希望這會起作用。

+1

拿去,這是不列那麼名稱 – sakir

+0

?根據你在做什麼排序desc? – Nithesh

+0

不行,它不是列名。它已經是column_name了 – sakir

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 
0

嘗試使用這樣的:

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' 
2

我加入一個答案,因爲很多其他的答案表明動態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; 
+0

我認爲它目前是(截至2018年2月)的優先解決方案,但我應該指出,該選項僅在MS SQL Server 2012版後纔可用,請參閱:http://www.sqlservergeeks.com/t-sql -paging-存儲過程/ – pholpar

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