SQL Server에서 결과 페이지를 매기는 가장 좋은 방법은 무엇입니까


474

총 페이지 수 (페이지 매기기 전)를 얻으려면 SQL Server 2000, 2005, 2008, 2012에서 결과 페이지를 매기는 가장 좋은 방법 (성능 현명한 방법)은 무엇입니까?


26
나는 왜 그들이 왜 TOP의 일부로 오프셋을 지정하지 않는지 궁금해했습니다 (LIMIT / OFFSET을 사용한 MySQL / Posgresql 지원과 같은). 예를 들어, "SELECT TOP x, y ...."구문을 가질 수 있습니다. 여기서 x = 행 수, y = 시작 오프셋. 또한 이전 버전과 호환됩니다.
gregmac


6
@gregmac-Sql Server 2012에는 이제 제한 / 오프셋이 있습니다.
OO

2
수용된 솔루션은 그것이 최선의 방법 (성능 현명한 방법)을 보여주지 않습니다. 대용량 데이터 세트에 백업하는 데이터가 있습니까?
OO

3
@OO, • 좋은 벤치 마크는 여기에서 찾을 수 있습니다 : 4guysfromrolla.com/webtech/042606-1.shtml . 그러나 seek 메소드 는 오프셋 기반 페이지 매김보다 성능이 우수합니다.
Lukas Eder

답변:


465

총 결과 수와 페이지 매김을 얻는 것은 두 가지 다른 작업입니다. 이 예제를 위해 다루고있는 쿼리가 다음과 같다고 가정 해 봅시다.

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 행을 반환합니다. 여기에서 특히 웹 앱의 경우 멋진 점은 반환 할 행 번호를 제외하고는 상태를 유지할 필요가 없다는 것입니다.


37
ROW_NUMBER ()는 SQL Server 2000에 존재하지 않습니다
John Hunter

6
내부 쿼리에서 모든 행을 반환 한 다음 외부 쿼리를 기준으로 필터링합니까? 예를 들어 : 내부 쿼리는 100,000을 반환하고 외부 쿼리는 20 만 반환합니다.
SoftwareGeek

2
@SoftwareGeek : 스트림을 반환하는 하위 쿼리 (내부 쿼리)로 생각하면 외부 WHERE 절이 충족 될 때까지 읽습니다. 행이 어떻게 관련되는지는 전적으로 쿼리에 달려 있지만 최적화 프로그램은 일반적으로 해당 숫자를 최소화하는 데 매우 효과적입니다. SQL Server Management Studio에서 그래픽 실행 계획 뷰어 사용 (실제 실행 계획 쿼리 / 포함 사용)은 매우 교육적입니다.
mdb

2
좋아, 당신은 (당신이 내부 때 가입 등) ROWNUMBER는 다르며 때문에 별개의 사용 어떻게 내 선택에 dublicated받을 경우 어떻게 그것이 작동하지 않음
user217648

10
Microsoft는 페이지 매김을 MySQL과 유사하게 만드는 새로운 기능을 SQL 2012에 추가했습니다. 방법을 배우려면이 링크를 따르십시오. 흥미로운 기사입니다 : dbadiaries.com/…
Arash

511

드디어, Microsoft SQL Server 2012 가 출시되었습니다. 페이지 매김의 단순함이 정말 마음에 듭니다. 여기서 답변 한 것과 같은 복잡한 쿼리를 사용할 필요가 없습니다.

다음 10 개 행을 얻으려면 다음 쿼리를 실행하십시오.

SELECT * FROM TableName ORDER BY id OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;

https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql#using-offset-and-fetch-to-limit-the-rows- 반환

그것을 사용할 때 고려해야 할 요점 :

  • ORDER BY 사용이 필수적이다 OFFSET ... FETCH조항 합니다.
  • OFFSET 이 조항은 필수입니다 FETCH . 사용할 수 없습니다 ORDER BY ... FETCH.
  • TOP동일한 쿼리 표현식 OFFSET과 결합하여 사용할 수 없습니다 FETCH.

12
LISTAGG()/에서 계속 기다리고 있습니다 GROUP_CONCAT().
베이컨 비트

1
@BaconBits 함께 그 일의 비열한 방법을이 답변을 참조하십시오 FOR XML: stackoverflow.com/a/273330/429949
리처드 Marskell - Drackir

1
@ RichardMarskell-Drackir에 많은 문제가 FOR XML PATH ('')있습니다. 먼저 XML 제어 문자를 XML 엔티티 코드로 바꿉니다. 당신이하지 않았 으면 <, >또는 &데이터에! 둘째, FOR XML PATH ('')이러한 방식으로 사용되는 것은 실제로 문서화되지 않은 구문입니다. 명명 된 열 또는 대체 요소 이름을 지정해야합니다. 문서에 둘 다없는 것은 동작이 신뢰할 수 없음을 의미합니다. 셋째, 깨진 FOR XML PATH ('')구문을 더 많이 받아들 일수록 MS는 실제로 필요한 실제 LISTAGG() [ OVER() ] 기능을 제공 할 가능성이 줄어 듭니다 .
베이컨 비트


5
@Jon, 링크 된 블로그 게시물은 대표적이지 않으므로 ID 열의 값을 조회하여 페이지 결과를 반환하여 비교합니다.
노엘 아브라함

103

놀랍게도, 모든 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(*).


2
@ user960567 : 성능면에서 키셋 페이징은 SQL 표준으로 오프셋 페이징을 구현하든 OFFSET .. FETCH이전 ROW_NUMBER()트릭으로 페이징을 수행하든 항상 오프셋 페이징을 능가합니다 .
Lukas Eder

21
검색 방법에 세 가지 문제가 있습니다. [1] 사용자가 페이지로 이동할 수 없습니다. [2] 순차적 인 키를 가정합니다. 예를 들어 누군가가 3 행을 삭제하면 10 대신 7 항목의 RowNumber페이지가 나타납니다. [3] 그것은 가정 기존 그리드와 함께 작동하지 않습니다 pagenumberpagesize.
Rebecca

7
@ Junto : 키 세트 페이징이 모든 경우에 적합한 것은 아닙니다. 데이터 그리드를위한 것은 아닙니다. 그러나 Facebook 피드 페이지의 무한 스크롤과 같은 시나리오에 적합합니다. 새 게시물을 맨 위에 추가해도 상관 없습니다. 아래로 스크롤하는 동안 후속 피드 게시물이 맨 아래에 올바르게 추가됩니다. 이것에 대한 완벽한 사용법 예제 ... 그러한 것들은 숫자 만 사용하여 오프셋 한계 / 페치를 사용하여 구현하는 것이 훨씬 어려울 것입니다 .
Robert Koritnik

4
Junto에 동의해야합니다. 이 방법은 사용자가 앞으로 나아갈 수있는 "이전 1 2 3 (4) 5 6 다음"과 같은 표준 페이지 매김 UI가있는 클라이언트를 완전히 배제합니다. 이것은 내 경험에서 가장
중요한

3
키 집합 페이지 매김 기사 여기
Stphane

31

SQL Server 2012에서 OFFSETFETCH 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;

TechNet : SQL Server를 사용하여 쿼리 페이징


이 시험에서 가장 정확한 답변
Vikrant

17

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

15

http://www.codeproject.com/KB/aspnet/PagingLarge.aspx 에는 다양한 페이징 기술에 대한 개요가 있습니다 .

ROWCOUNT 방법을 주로 SQL Server 2000에서 자주 사용했습니다 (2005 및 2008에서도 작동하고 ROW_NUMBER와 비교하여 성능 만 측정). 번개는 빠르지 만 정렬 된 열이 (주로 ) 고유 한 값.


1
흥미롭게도,이 기사는 일정한 시간에 페이징을 수행 할 수 있는 seek 메소드를 언급하지 않습니다 ... 여전히 좋은 기사
Lukas Eder

6

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가 사용되었습니다.


3

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

2

이들은 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;

1

이 접근법을 시도하십시오 :

SELECT TOP @offset a.*
FROM (select top @limit b.*, COUNT(*) OVER() totalrows 
        from TABLENAME b order by id asc) a
ORDER BY id desc;

1

유스 케이스는 다음과 같이 사용하기 쉽고 빠릅니다. 페이지 번호를 설정하십시오.

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)

1
1 = 1은 어디에 있습니까?
Errol Paleracio '1

0

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 텍스트가 생성됩니다.


0
   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를 다시 시작합니다.


0

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을 가져옵니다.


페이지 매김을 사용하면 순서를 보장 된 것으로 생각해서는 안되므로 결과 집합에서 고유 한 열 집합을 사용하여 순서를 지정하는 것이 좋습니다.
Arin Taylor

2
이것은 레코드 11에서 30을 가져옵니다.
Ardalan Shahgholi

0
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

0

이 비트는 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

코드의 기능을 설명하는 의견을 남겨주시겠습니까?
Doug F


0

2012 년부터 사용할 수 있습니다 OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY


-19

언어 나 사용중인 드라이버를 지정하지 않았습니다. 따라서 나는 그것을 추상적으로 설명하고 있습니다.

  • 스크롤 가능한 결과 집합 / 데이터 집합을 만듭니다. 이것은 테이블에서 기본이 필요했습니다.
  • 끝으로 뛰어
  • 행 개수 요청
  • 페이지의 시작으로 이동
  • 페이지 끝까지 행을 스크롤
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.