총 페이지 수 (페이지 매기기 전)를 얻으려면 SQL Server 2000, 2005, 2008, 2012에서 결과 페이지를 매기는 가장 좋은 방법 (성능 현명한 방법)은 무엇입니까?
총 페이지 수 (페이지 매기기 전)를 얻으려면 SQL Server 2000, 2005, 2008, 2012에서 결과 페이지를 매기는 가장 좋은 방법 (성능 현명한 방법)은 무엇입니까?
답변:
총 결과 수와 페이지 매김을 얻는 것은 두 가지 다른 작업입니다. 이 예제를 위해 다루고있는 쿼리가 다음과 같다고 가정 해 봅시다.
SELECT * FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate
이 경우 다음을 사용하여 총 결과 수를 결정합니다.
SELECT COUNT(*) FROM Orders WHERE OrderDate >= '1980-01-01'
... 비효율적 인 것처럼 보일 수 있지만 모든 색인 등이 올바르게 설정되었다고 가정하면 실제로 성능이 뛰어납니다.
다음으로 실제 결과를 페이지 방식으로 되돌리려면 다음 쿼리가 가장 효율적입니다.
SELECT *
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY OrderDate ) AS RowNum, *
FROM Orders
WHERE OrderDate >= '1980-01-01'
) AS RowConstrainedResult
WHERE RowNum >= 1
AND RowNum < 20
ORDER BY RowNum
원래 쿼리의 1-19 행을 반환합니다. 여기에서 특히 웹 앱의 경우 멋진 점은 반환 할 행 번호를 제외하고는 상태를 유지할 필요가 없다는 것입니다.
드디어, Microsoft SQL Server 2012 가 출시되었습니다. 페이지 매김의 단순함이 정말 마음에 듭니다. 여기서 답변 한 것과 같은 복잡한 쿼리를 사용할 필요가 없습니다.
다음 10 개 행을 얻으려면 다음 쿼리를 실행하십시오.
SELECT * FROM TableName ORDER BY id OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
그것을 사용할 때 고려해야 할 요점 :
ORDER BY
사용이 필수적이다 OFFSET ... FETCH
조항 합니다.OFFSET
이 조항은 필수입니다 FETCH
. 사용할 수 없습니다 ORDER BY ...
FETCH
.TOP
동일한 쿼리 표현식 OFFSET
과 결합하여 사용할 수 없습니다 FETCH
.LISTAGG()
/에서 계속 기다리고 있습니다 GROUP_CONCAT()
.
FOR XML
: stackoverflow.com/a/273330/429949
FOR XML PATH ('')
있습니다. 먼저 XML 제어 문자를 XML 엔티티 코드로 바꿉니다. 당신이하지 않았 으면 <
, >
또는 &
데이터에! 둘째, FOR XML PATH ('')
이러한 방식으로 사용되는 것은 실제로 문서화되지 않은 구문입니다. 명명 된 열 또는 대체 요소 이름을 지정해야합니다. 문서에 둘 다없는 것은 동작이 신뢰할 수 없음을 의미합니다. 셋째, 깨진 FOR XML PATH ('')
구문을 더 많이 받아들 일수록 MS는 실제로 필요한 실제 LISTAGG() [ OVER() ]
기능을 제공 할 가능성이 줄어 듭니다 .
놀랍게도, 모든 SQL Server 버전에서 페이지 매김을 수행 하는 가장 빠른 방법을 언급 한 다른 답변은 없습니다 . 여기에서 벤치마킹 된 것처럼 큰 페이지 번호의 경우 오프셋이 매우 느려질 수 있습니다 . SQL에서 페이지 매김을 수행하는 완전히 다른 방법이 있습니다. 이 블로그 게시물 here에 설명 된대로이를 "검색 방법"또는 "키셋 페이지 매김"이라고 합니다 .
SELECT TOP 10 first_name, last_name, score, COUNT(*) OVER()
FROM players
WHERE (score < @previousScore)
OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC
@previousScore
및 @previousPlayerId
값은 이전 페이지에서 마지막 레코드의 각각의 값입니다. "다음"페이지를 가져올 수 있습니다. 경우 ORDER BY
방향은 ASC
단순히 사용>
대신.
위의 방법을 사용하면 이전 40 개의 레코드를 먼저 가져 오지 않고 4 페이지로 바로 이동할 수 없습니다. 그러나 종종, 당신은 어쨌든 그렇게 멀리 뛰어 가고 싶지 않습니다. 대신 인덱싱에 따라 일정한 시간에 데이터를 가져올 수있는 훨씬 빠른 쿼리를 얻습니다. 또한 기본 데이터가 변경 되더라도 (예 : 4 페이지, 1 페이지) 페이지가 "안정적"으로 유지됩니다.
예를 들어 웹 응용 프로그램에서 더 많은 데이터를 지연로드 할 때 페이지 매김을 구현하는 가장 좋은 방법입니다.
"검색 방법"은 키 세트 페이지 매김 이라고도합니다. 합니다.
COUNT(*) OVER()
윈도우 함수는 "매김하기 전에"총 레코드 수를 계산하는 데 도움이됩니다. SQL Server 2000을 사용하는 경우에 대한 두 개의 쿼리를 사용해야합니다 COUNT(*)
.
OFFSET .. FETCH
이전 ROW_NUMBER()
트릭으로 페이징을 수행하든 항상 오프셋 페이징을 능가합니다 .
RowNumber
페이지가 나타납니다. [3] 그것은 가정 기존 그리드와 함께 작동하지 않습니다 pagenumber
와 pagesize
.
SQL Server 2012에서 OFFSET
및 FETCH NEXT
절을 사용 하여 페이지 매김을 달성 할 수 있습니다 .
SQL Server의 경우 다음을 시도하십시오.
SQL Server 2012에서는 ORDER BY 절에 새로운 기능이 추가되어 집합 데이터의 최적화를 쿼리하여 SQL Server의 전체 실행 계획뿐만 아니라 T-SQL로 작성하는 모든 사람의 데이터 페이징 작업이 쉬워졌습니다.
이전 예에서 사용한 것과 동일한 논리를 사용하는 T-SQL 스크립트 아래
--CREATING A PAGING WITH OFFSET and FETCH clauses IN "SQL SERVER 2012" DECLARE @PageNumber AS INT, @RowspPage AS INT SET @PageNumber = 2 SET @RowspPage = 10 SELECT ID_EXAMPLE, NM_EXAMPLE, DT_CREATE FROM TB_EXAMPLE ORDER BY ID_EXAMPLE OFFSET ((@PageNumber - 1) * @RowspPage) ROWS FETCH NEXT @RowspPage ROWS ONLY;
MSDN : ROW_NUMBER (Transact-SQL)
각 파티션의 첫 번째 행에 대해 1부터 시작하여 결과 세트의 파티션 내에서 행의 순차 번호를 리턴합니다.
다음 예제는 OrderDate 순서로 숫자가 50-60 인 행을 리턴합니다.
WITH OrderedOrders AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY FirstName DESC) AS RowNumber,
FirstName, LastName, ROUND(SalesYTD,2,1) AS "Sales YTD"
FROM [dbo].[vSalesPerson]
)
SELECT RowNumber,
FirstName, LastName, Sales YTD
FROM OrderedOrders
WHERE RowNumber > 50 AND RowNumber < 60;
RowNumber FirstName LastName SalesYTD
--- ----------- ---------------------- -----------------
1 Linda Mitchell 4251368.54
2 Jae Pak 4116871.22
3 Michael Blythe 3763178.17
4 Jillian Carson 3189418.36
5 Ranjit Varkey Chudukatil 3121616.32
6 José Saraiva 2604540.71
7 Shu Ito 2458535.61
8 Tsvi Reiter 2315185.61
9 Rachel Valdez 1827066.71
10 Tete Mensa-Annan 1576562.19
11 David Campbell 1573012.93
12 Garrett Vargas 1453719.46
13 Lynn Tsoflias 1421810.92
14 Pamela Ansman-Wolfe 1352577.13
http://www.codeproject.com/KB/aspnet/PagingLarge.aspx 에는 다양한 페이징 기술에 대한 개요가 있습니다 .
ROWCOUNT 방법을 주로 SQL Server 2000에서 자주 사용했습니다 (2005 및 2008에서도 작동하고 ROW_NUMBER와 비교하여 성능 만 측정). 번개는 빠르지 만 정렬 된 열이 (주로 ) 고유 한 값.
SQL Server 2000의 경우 IDENTITY 열이있는 테이블 변수를 사용하여 ROW_NUMBER ()를 시뮬레이션 할 수 있습니다.
DECLARE @pageNo int -- 1 based
DECLARE @pageSize int
SET @pageNo = 51
SET @pageSize = 20
DECLARE @firstRecord int
DECLARE @lastRecord int
SET @firstRecord = (@pageNo - 1) * @pageSize + 1 -- 1001
SET @lastRecord = @firstRecord + @pageSize - 1 -- 1020
DECLARE @orderedKeys TABLE (
rownum int IDENTITY NOT NULL PRIMARY KEY CLUSTERED,
TableKey int NOT NULL
)
SET ROWCOUNT @lastRecord
INSERT INTO @orderedKeys (TableKey) SELECT ID FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate
SET ROWCOUNT 0
SELECT t.*
FROM Orders t
INNER JOIN @orderedKeys o ON o.TableKey = t.ID
WHERE o.rownum >= @firstRecord
ORDER BY o.rownum
이 방법은 다중 열 키가있는 테이블로 확장 될 수 있으며 OR (인덱스 사용을 건너 뛰는)을 사용하는 경우 성능 오버 헤드가 발생하지 않습니다. 단점은 데이터 세트가 매우 크고 마지막 페이지에 가까운 경우 사용 된 임시 공간의 양입니다. 이 경우 커서 성능을 테스트하지는 않았지만 더 좋을 수 있습니다.
이 방법은 데이터의 첫 페이지에 최적화 될 수 있습니다. 또한 TOP은 SQL Server 2000에서 변수를 허용하지 않으므로 ROWCOUNT가 사용되었습니다.
SQL Server 2012에서 페이징을 수행하는 가장 좋은 방법은 저장 프로 시저에서 오프셋과 페치를 사용하는 것입니다. OFFSET 키워드-order by 절과 함께 offset을 사용하면 쿼리는 OFFSET n Rows에 지정한 레코드 수를 건너 뜁니다.
FETCH NEXT 키워드-order by 절과 함께 Fetch Next를 사용하면 페이징에 표시하려는 행 수를 오프셋없이 반환하고 SQL은 오류를 생성합니다. 다음은 아래 예입니다.
create procedure sp_paging
(
@pageno as int,
@records as int
)
as
begin
declare @offsetcount as int
set @offsetcount=(@pageno-1)*@records
select id,bs,variable from salary order by id offset @offsetcount rows fetch Next @records rows only
end
다음과 같이 실행할 수 있습니다.
exec sp_paging 2,3
이들은 SQL 서버 측에서 쿼리 결과를 페이징하는 솔루션입니다. 이러한 접근 방식은 SQL Server 2008과 2012에서 서로 다릅니다. 또한 필터링 및 순서 개념을 하나의 열로 추가했습니다. Gridview에서 페이징, 필터링 및 주문할 때 매우 효율적입니다.
테스트하기 전에 하나의 샘플 테이블을 작성하고이 테이블에 행을 삽입해야합니다. (실제에서는 테이블 필드를 고려하여 Where 절을 변경해야하며 select의 주요 부분에 조인 및 하위 쿼리가있을 수 있습니다)
Create Table VLT
(
ID int IDentity(1,1),
Name nvarchar(50),
Tel Varchar(20)
)
GO
Insert INTO VLT
VALUES
('NAME' + Convert(varchar(10),@@identity),'FAMIL' + Convert(varchar(10),@@identity))
GO 500000
이 모든 샘플에서 페이지 당 200 행을 쿼리하고 페이지 번호 1200에 대한 행을 가져옵니다.
SQL Server 2008에서는 CTE 개념을 사용할 수 있습니다. 이 때문에 SQL Server 2008+에 대해 두 가지 유형의 쿼리를 작성했습니다.
-SQL Server 2008+
DECLARE @PageNumber Int = 1200
DECLARE @PageSize INT = 200
DECLARE @SortByField int = 1 --The field used for sort by
DECLARE @SortOrder nvarchar(255) = 'ASC' --ASC or DESC
DECLARE @FilterType nvarchar(255) = 'None' --The filter type, as defined on the client side (None/Contain/NotContain/Match/NotMatch/True/False/)
DECLARE @FilterValue nvarchar(255) = '' --The value the user gave for the filter
DECLARE @FilterColumn int = 1 --The column to wich the filter is applied, represents the column number like when we send the information.
SELECT
Data.ID,
Data.Name,
Data.Tel
FROM
(
SELECT
ROW_NUMBER()
OVER( ORDER BY
CASE WHEN @SortByField = 1 AND @SortOrder = 'ASC'
THEN VLT.ID END ASC,
CASE WHEN @SortByField = 1 AND @SortOrder = 'DESC'
THEN VLT.ID END DESC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'ASC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'DESC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'ASC'
THEN VLT.Tel END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'DESC'
THEN VLT.Tel END ASC
) AS RowNum
,*
FROM VLT
WHERE
( -- We apply the filter logic here
CASE
WHEN @FilterType = 'None' THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 1
AND VLT.ID = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 1
AND VLT.ID <> @FilterValue THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 2
AND VLT.Name = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 2
AND VLT.Name <> @FilterValue THEN 1
-- Tel column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 3
AND VLT.Tel = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 3
AND VLT.Tel <> @FilterValue THEN 1
END
) = 1
) AS Data
WHERE Data.RowNum > @PageSize * (@PageNumber - 1)
AND Data.RowNum <= @PageSize * @PageNumber
ORDER BY Data.RowNum
GO
SQL Server 2008+에서 CTE를 사용하는 두 번째 솔루션
DECLARE @PageNumber Int = 1200
DECLARE @PageSize INT = 200
DECLARE @SortByField int = 1 --The field used for sort by
DECLARE @SortOrder nvarchar(255) = 'ASC' --ASC or DESC
DECLARE @FilterType nvarchar(255) = 'None' --The filter type, as defined on the client side (None/Contain/NotContain/Match/NotMatch/True/False/)
DECLARE @FilterValue nvarchar(255) = '' --The value the user gave for the filter
DECLARE @FilterColumn int = 1 --The column to wich the filter is applied, represents the column number like when we send the information.
;WITH
Data_CTE
AS
(
SELECT
ROW_NUMBER()
OVER( ORDER BY
CASE WHEN @SortByField = 1 AND @SortOrder = 'ASC'
THEN VLT.ID END ASC,
CASE WHEN @SortByField = 1 AND @SortOrder = 'DESC'
THEN VLT.ID END DESC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'ASC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'DESC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'ASC'
THEN VLT.Tel END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'DESC'
THEN VLT.Tel END ASC
) AS RowNum
,*
FROM VLT
WHERE
( -- We apply the filter logic here
CASE
WHEN @FilterType = 'None' THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 1
AND VLT.ID = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 1
AND VLT.ID <> @FilterValue THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 2
AND VLT.Name = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 2
AND VLT.Name <> @FilterValue THEN 1
-- Tel column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 3
AND VLT.Tel = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 3
AND VLT.Tel <> @FilterValue THEN 1
END
) = 1
)
SELECT
Data.ID,
Data.Name,
Data.Tel
FROM Data_CTE AS Data
WHERE Data.RowNum > @PageSize * (@PageNumber - 1)
AND Data.RowNum <= @PageSize * @PageNumber
ORDER BY Data.RowNum
-SQL Server 2012 이상
DECLARE @PageNumber Int = 1200
DECLARE @PageSize INT = 200
DECLARE @SortByField int = 1 --The field used for sort by
DECLARE @SortOrder nvarchar(255) = 'ASC' --ASC or DESC
DECLARE @FilterType nvarchar(255) = 'None' --The filter type, as defined on the client side (None/Contain/NotContain/Match/NotMatch/True/False/)
DECLARE @FilterValue nvarchar(255) = '' --The value the user gave for the filter
DECLARE @FilterColumn int = 1 --The column to wich the filter is applied, represents the column number like when we send the information.
;WITH
Data_CTE
AS
(
SELECT
*
FROM VLT
WHERE
( -- We apply the filter logic here
CASE
WHEN @FilterType = 'None' THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 1
AND VLT.ID = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 1
AND VLT.ID <> @FilterValue THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 2
AND VLT.Name = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 2
AND VLT.Name <> @FilterValue THEN 1
-- Tel column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 3
AND VLT.Tel = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 3
AND VLT.Tel <> @FilterValue THEN 1
END
) = 1
)
SELECT
Data.ID,
Data.Name,
Data.Tel
FROM Data_CTE AS Data
ORDER BY
CASE WHEN @SortByField = 1 AND @SortOrder = 'ASC'
THEN Data.ID END ASC,
CASE WHEN @SortByField = 1 AND @SortOrder = 'DESC'
THEN Data.ID END DESC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'ASC'
THEN Data.Name END ASC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'DESC'
THEN Data.Name END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'ASC'
THEN Data.Tel END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'DESC'
THEN Data.Tel END ASC
OFFSET @PageSize * (@PageNumber - 1) ROWS FETCH NEXT @PageSize ROWS ONLY;
유스 케이스는 다음과 같이 사용하기 쉽고 빠릅니다. 페이지 번호를 설정하십시오.
use AdventureWorks
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 6;
with result as(
SELECT SalesOrderDetailID, SalesOrderID, ProductID,
ROW_NUMBER() OVER (ORDER BY SalesOrderDetailID) AS RowNum
FROM Sales.SalesOrderDetail
where 1=1
)
select SalesOrderDetailID, SalesOrderID, ProductID from result
WHERE result.RowNum BETWEEN ((@PageNumber-1)*@RowsPerPage)+1
AND @RowsPerPage*(@PageNumber)
또한 CTE없이
use AdventureWorks
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 6
SELECT SalesOrderDetailID, SalesOrderID, ProductID
FROM (
SELECT SalesOrderDetailID, SalesOrderID, ProductID,
ROW_NUMBER() OVER (ORDER BY SalesOrderDetailID) AS RowNum
FROM Sales.SalesOrderDetail
where 1=1
) AS SOD
WHERE SOD.RowNum BETWEEN ((@PageNumber-1)*@RowsPerPage)+1
AND @RowsPerPage*(@PageNumber)
SQL 2000 데이터베이스에서 다음 샘플 쿼리를 사용했는데 SQL 2005에서도 잘 작동합니다. 그것이 제공하는 힘은 여러 열을 사용하여 동적으로 정렬됩니다. 나는 당신에게 말한다 ... 이것은 강력하다 :)
ALTER PROCEDURE [dbo].[RE_ListingReports_SelectSummary]
@CompanyID int,
@pageNumber int,
@pageSize int,
@sort varchar(200)
AS
DECLARE @sql nvarchar(4000)
DECLARE @strPageSize nvarchar(20)
DECLARE @strSkippedRows nvarchar(20)
DECLARE @strFields nvarchar(4000)
DECLARE @strFilter nvarchar(4000)
DECLARE @sortBy nvarchar(4000)
DECLARE @strFrom nvarchar(4000)
DECLARE @strID nvarchar(100)
If(@pageNumber < 0)
SET @pageNumber = 1
SET @strPageSize = CAST(@pageSize AS varchar(20))
SET @strSkippedRows = CAST(((@pageNumber - 1) * @pageSize) AS varchar(20))-- For example if pageNumber is 5 pageSize is 10, then SkippedRows = 40.
SET @strID = 'ListingDbID'
SET @strFields = 'ListingDbID,
ListingID,
[ExtraRoom]
'
SET @strFrom = ' vwListingSummary '
SET @strFilter = ' WHERE
CompanyID = ' + CAST(@CompanyID As varchar(20))
End
SET @sortBy = ''
if(len(ltrim(rtrim(@sort))) > 0)
SET @sortBy = ' Order By ' + @sort
-- Total Rows Count
SET @sql = 'SELECT Count(' + @strID + ') FROM ' + @strFROM + @strFilter
EXEC sp_executesql @sql
--// This technique is used in a Single Table pagination
SET @sql = 'SELECT ' + @strFields + ' FROM ' + @strFROM +
' WHERE ' + @strID + ' IN ' +
' (SELECT TOP ' + @strPageSize + ' ' + @strID + ' FROM ' + @strFROM + @strFilter +
' AND ' + @strID + ' NOT IN ' + '
(SELECT TOP ' + @strSkippedRows + ' ' + @strID + ' FROM ' + @strFROM + @strFilter + @SortBy + ') '
+ @SortBy + ') ' + @SortBy
Print @sql
EXEC sp_executesql @sql
가장 좋은 부분은 sp_executesql이 나중에 호출을 캐시하는 것입니다. 동일한 매개 변수를 전달하면 동일한 SQL 텍스트가 생성됩니다.
CREATE view vw_sppb_part_listsource as
select row_number() over (partition by sppb_part.init_id order by sppb_part.sppb_part_id asc ) as idx, * from (
select
part.SPPB_PART_ID
, 0 as is_rev
, part.part_number
, part.init_id
from t_sppb_init_part part
left join t_sppb_init_partrev prev on ( part.SPPB_PART_ID = prev.SPPB_PART_ID )
where prev.SPPB_PART_ID is null
union
select
part.SPPB_PART_ID
, 1 as is_rev
, prev.part_number
, part.init_id
from t_sppb_init_part part
inner join t_sppb_init_partrev prev on ( part.SPPB_PART_ID = prev.SPPB_PART_ID )
) sppb_part
다른 init_id와 관련하여 idx를 다시 시작합니다.
이 ROW_NUMBER
기술의 경우 사용할 정렬 열이 없으면 CURRENT_TIMESTAMP
다음을 사용할 수 있습니다 .
SELECT TOP 20
col1,
col2,
col3,
col4
FROM (
SELECT
tbl.col1 AS col1
,tbl.col2 AS col2
,tbl.col3 AS col3
,tbl.col4 AS col4
,ROW_NUMBER() OVER (
ORDER BY CURRENT_TIMESTAMP
) AS sort_row
FROM dbo.MyTable tbl
) AS query
WHERE query.sort_row > 10
ORDER BY query.sort_row
이것은 심지어 최대 70 만 개의 테이블 크기를 검색하는 데 효과적이었습니다.
레코드 11에서 30을 가져옵니다.
create PROCEDURE SP_Company_List (@pagesize int = -1 ,@pageindex int= 0 ) > AS BEGIN SET NOCOUNT ON; select Id , NameEn from Company ORDER by Id ASC OFFSET (@pageindex-1 )* @pagesize ROWS FETCH NEXt @pagesize ROWS ONLY END GO
DECLARE @return_value int EXEC @return_value = [dbo].[SP_Company_List] @pagesize = 1 , > @pageindex = 2 SELECT 'Return Value' = @return_value GO
이 비트는 SQL Server 및 최신 버전의 MySQL을 사용하여 페이지 매김 기능을 제공하며 모든 행의 총 행 수를 전달합니다. pimary 키를 사용하여 고유 한 행 수를 계산합니다.
WITH T AS
(
SELECT TABLE_ID, ROW_NUMBER() OVER (ORDER BY TABLE_ID) AS RN
, (SELECT COUNT(TABLE_ID) FROM TABLE) AS TOTAL
FROM TABLE (NOLOCK)
)
SELECT T2.FIELD1, T2.FIELD2, T2.FIELD3, T.TOTAL
FROM TABLE T2 (NOLOCK)
INNER JOIN T ON T2.TABLE_ID=T.TABLE_ID
WHERE T.RN >= 100
AND T.RN < 200
이것은 2012 년의 오래된 SO 질문과 중복됩니다 : 효율적인 페이징 구현 방법
[TableX]에서 주문 [FieldX] 오프셋 500 ROWS FETCH NEXT 100 ROWS 만 해당
여기 에서 주제에 대해 더 자세하게 설명하고 다른 방법으로 설명합니다.