SQL Server의 LIMIT 10..20


161

나는 다음과 같은 일을하려고합니다.

SELECT * FROM table LIMIT 10,20

또는

SELECT * FROM table LIMIT 10 OFFSET 10

그러나 SQL Server 사용

내가 찾은 유일한 솔루션 은 과잉처럼 보입니다.

SELECT * FROM ( 
  SELECT *, ROW_NUMBER() OVER (ORDER BY name) as row FROM sys.databases 
 ) a WHERE row > 5 and row <= 10

나는 또한 발견했다 :

SELECT TOP 10 * FROM stuff; 

...하지만 시작 한계를 지정할 수 없기 때문에 내가하고 싶은 것이 아닙니다.

내가 할 수있는 또 다른 방법이 있습니까?

또한 궁금한 점이 있는데 SQL Server가 LIMIT함수 또는 이와 유사한 기능을 지원하지 않는 이유가 있습니까? 나는 의미가되고 싶지 않지만 DBMS가 필요로하는 것처럼 들린다. 만약 그렇다면, 그렇게 무지한 것이 유감 스럽다! 지난 5 년간 MySQL 및 SQL +와 함께 일해 왔습니다.


1
CTE를 사용 하여 범위의 너비와 범위를 ROW_NUMBER()제한 TOP하고 범위 WHERE의 경계 조건을 달성하는 것이 가장 좋습니다. 경우 나는 훨씬 더 나은 성능을 나타났습니다 TOP절은 변수 대신 문자를 사용
Jodrell

ROW_NUMBER ()와 관련된 솔루션의 문제점은 어떤 열을 미리 알 수없고 조인이 있고 조인 된 테이블의 열 이름이 같으면 "The column 'xxx'이 (가) 여러 번 지정되었습니다. " 처음에 들리는 것만 큼 드문 일이 아닙니다. Dapper를 사용하며 테이블에는 모두 ID 열이 있습니다. Dapper는 그 부분을 분할하고 매핑하므로 이름을 바꾸고 싶지 않지만 SELECT * FROM ([원래 쿼리]) 별칭을 사용할 수 없습니다. 아직 해결책을 찾지 못했습니다!
Steve Owen

답변:


104

LIMIT절은 표준 SQL의 일부가 아닙니다. MySQL, PostgreSQL 및 SQLite에서 SQL에 대한 공급 업체 확장으로 지원됩니다.

다른 브랜드의 데이터베이스는 유사한 기능 (예 : TOPMicrosoft SQL Server)을 가질 수 있지만 항상 동일하게 작동하지는 않습니다.

조항 TOP을 모방하기 위해 Microsoft SQL Server에서 사용하기가 어렵습니다 LIMIT. 작동하지 않는 경우가 있습니다.

사용하여 표시 한 솔루션 ROW_NUMBER()은 Microsoft SQL Server 2005 이상에서 사용할 수 있습니다. 이것은 쿼리의 일부로 만 작동하는 (현재로서는) 최상의 솔루션입니다.

또 다른 해결책은 TOP첫 번째 카운트 + 오프셋 행을 가져온 다음 API를 사용하여 첫 번째 오프셋 행을 지나서 찾는 것 입니다.

또한보십시오:


135

SQL Server 2012 +의 경우을 사용할 수 있습니다 .

SELECT  *
FROM     sys.databases
ORDER BY name 
OFFSET  5 ROWS 
FETCH NEXT 5 ROWS ONLY 

10
SQl Server 2012에서는 OFFSET 5 ROWS FETCH NEXT 5 ROWS 만 사용할 때 ORDER BY를 지정해야하지만, LIMIT 5,5를 사용할 때는 MySql 및 SQLite에 ORDER BY가 필요하지 않습니다.
Tomas Kubes

4
@ qub1n-MySQL 은이 경우 어떤 행으로 돌아 오는지를 보장하지 않습니다 .
Martin Smith

3
을 사용해야합니까 offset, 아니면 오프셋을 원하지 않는다고 가정하여 해당 라인을 그대로 둘 수 있습니까?
Cullub


당신은 예를 들어 쿼리가 벌금을 실행하지만 SELECT 아래와 같이 COL하여 테이블 이름과 순서를 변경하는 경우 DimProduct ORDER BY의 Productkey 5 개 행을 OFFSET * FROM 다음의 5 개 행을 FETCH ONLY는 오류 제공Parse error at line: 4, column: 1: Incorrect syntax near 'OFFSET'
shashwat

36

알다시피, 이것은 선호되는 SQL 서버 방법입니다.

SELECT * FROM ( 
  SELECT *, ROW_NUMBER() OVER (ORDER BY name) as row FROM sys.databases 
 ) a WHERE a.row > 5 and a.row <= 10

a내부 선택 후? 내부 선택에 별칭을 부여한다고 가정하지만 결코 사용하지 않는 것 같습니다 ... 그렇다면 a.row대신 대신 해야합니까 row?
Lucas

3
@Lucas, ( )파생 테이블 뒤에 별칭을 입력해야 하지만 열을 참조하는 데 사용하지 않는 경우 별칭을 놓을 수 있습니다. 나는 그것을 고쳤다
.

고마워, 나는 그 어려운 길을 찾았습니다 (별명을 남기려고 노력했습니다).
Lucas

1
+1 투표 : 그러나 @MartinSmith의 답변 은 실행 계획을이 접근법과 비교 한 후 더 많이 투표되었습니다.이 솔루션이 더 빨리 작동한다는 것을 알았습니다.
Harsh

10

Martin Smith의 답변에 대해 SQL Server 2012 이상 투표를 사용 OFFSET하고에 FETCH NEXT확장명을 사용하는 경우 ORDER BY,

불행히도 이전 버전을 고수 할 수 있다면 다음과 같이 할 수 있습니다.

WITH Rows AS
(
    SELECT
              ROW_NUMBER() OVER (ORDER BY [dbo].[SomeColumn]) [Row]
            , *
        FROM
              [dbo].[SomeTable]
)
SELECT TOP 10
          *
     FROM
         Rows
    WHERE Row > 10

나는 기능적이라고 생각합니다

SELECT * FROM SomeTable LIMIT 10 OFFSET 10 ORDER BY SomeColumn

그리고 MS SQL 2012 이전에 TSQL에서 내가 아는 최고의 성능.


행이 매우 많은 경우 CTE 대신 임시 테이블을 사용하여 성능을 향상시킬 수 있습니다.


2012 년 이전 솔루션을 제공하는 동안 Martin Smith의 답변을 지적하고 이에 연결하는 데 찬성했습니다. 또한 당신이 정확하기 때문에 임시 테이블 조언을 위해 :)
fujiiface

7

불행히도, ROW_NUMBER()당신이 할 수있는 최선입니다. limitor top절의 결과는 특정 순서와 관계없이 의미가 없기 때문에 실제로 더 정확합니다 . 그러나 여전히 고통 스럽습니다.

업데이트 : Sql Server 2012는 OFFSET 및 FETCH 키워드limit 를 통해 유사한 기능을 추가합니다 . 이는 표준 이 아닌 MySql 확장 인와 반대로 ansi-standard 방식 입니다.LIMIT


@Joel : ROW_NUMBER ()가 ORDER BY에서 나오는 방식으로 행 번호를 지정할 수없는 이유를 설명 할 수 있습니까? 나는 왜 "OVER (ORDER BY name)"이 필수인지 궁금해했지만 그만한 이유가 있다고 생각합니다. 또는 적어도 이유.
Tomalak 2016 년

3
order by 절이없는 order와 같은 것은 없기 때문입니다. 서버에서 레코드를 사용할 수있는 순서를 가져 오면 쿼리 요청에서 쿼리 요청으로 변경할있습니다 .
Joel Coehoorn

1
@marcgg : Microsoft가 LIMIT를 구현할 계획을 전혀 읽지 못했습니다. 이러한 계획이 있어도 비공개 소스 공급 업체는 기능을 미리 발표하지 않는 경향이 있습니다. 확실히 유용한 기능이지만 코드가 주어지면 얼마나 많은 작업을 수행해야하는지 알 수 없습니다.
Bill Karwin

3
ORDER BY 절에서 반복하지 않으려면 원래 열 세트 대신 ROW_NUMBER () 별명을 사용하십시오.
Peter Radocchia

2
@Tomalak : SQL Server와 관련하여 ROW_NUMBER ()를 계산하는 데 사용되는 순서는 결과 집합의 순서와 전혀 관련이 없습니다. 따라서 별도로 지정해야합니다.
LukeH 2016 년

6

이건 어때요?

SET ROWCOUNT 10 

SELECT TOP 20 *
FROM sys.databases
ORDER BY database_id DESC

처음 20 개 행 중 마지막 10 개 행을 제공합니다. 한 가지 단점은 순서가 반대로되어 있지만 적어도 기억하기 쉽다는 것입니다.


6
테이블에 14 개의 행만 있으면 어떻게됩니까? LIMIT 10 OFFSET 10에 의해 리턴 된 행과 동일하지 않은 14 행을 5 행으로 줄입니다 (14 행은 11 행).
Bill Karwin

2
SELECT TOP 10 *
FROM TABLE
WHERE IDCOLUMN NOT IN (SELECT TOP 10 IDCOLUMN FROM TABLE)

기록 11-20을 제공해야합니다. 추가 페이지를 얻기 위해 증분하는 경우에는 너무 비효율적이며 주문에 의해 어떻게 영향을받을 수 있는지 확실하지 않습니다. WHERE 문에서 이것을 지정해야 할 수도 있습니다.


1

좋은 방법은 절차를 만드는 것입니다.

create proc pagination (@startfrom int ,@endto int) as
SELECT * FROM ( 
  SELECT *, ROW_NUMBER() OVER (ORDER BY name desc) as row FROM sys.databases 
 ) a WHERE a.row > @startfrom and a.row <= @endto

한계 0,2와 마찬가지로 //////////////// 페이지 매김 실행 0,4


1

대부분의 데이터베이스 엔진에서 작동하는 레코드 솔루션의 경우 가장 효율적이지 않을 수 있습니다.

Select Top (ReturnCount) *
From (
    Select Top (SkipCount + ReturnCount) *
    From SourceTable
    Order By ReverseSortCondition
) ReverseSorted
Order By SortCondition

참고 사항 : 마지막 페이지에는 SkipCount가 무엇이든 관계없이 ReturnCount 행이 계속 포함됩니다. 그러나 그것은 많은 경우에 좋은 것일 수 있습니다.


1

LIMIT와 동등한 것은 SET ROWCOUNT이지만 일반 페이지 매김을 원하면 다음과 같은 쿼리를 작성하는 것이 좋습니다.

;WITH Results_CTE AS
(
    SELECT
        Col1, Col2, ...,
        ROW_NUMBER() OVER (ORDER BY SortCol1, SortCol2, ...) AS RowNum
    FROM Table
    WHERE <whatever>
)
SELECT *
FROM Results_CTE
WHERE RowNum >= @Offset
AND RowNum < @Offset + @Limit

0
select * from (select id,name,ROW_NUMBER() OVER (ORDER BY id  asc) as row
from tableName1) tbl1
where tbl1.row>=10 and tbl1.row<=15

10에서 15까지 행을 인쇄합니다.


0

지금 까지이 형식은 저에게 효과적입니다 (최상의 성능은 아니지만).

SELECT TOP {desired amount of rows} * 
FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY {order columns} asc)__row__ FROM {table})tmp
WHERE __row__ > {offset row count}

동적 데이터에 페이지를 매기면 이상한 / 예기치 않은 결과가 발생할 수 있습니다.


0

MS SQL Server 온라인 문서 ( http://technet.microsoft.com/en-us/library/ms186734.aspx )에서 특정 행 집합을 검색하기 위해 테스트하고 작동 한 예제가 있습니다. ROW_NUMBER에는 OVER가 필요하지만 원하는대로 주문할 수 있습니다.

WITH OrderedOrders AS
(
  SELECT SalesOrderID, OrderDate,
  ROW_NUMBER() OVER (ORDER BY OrderDate) AS RowNumber
  FROM Sales.SalesOrderHeader 
) 
SELECT SalesOrderID, OrderDate, RowNumber  
FROM OrderedOrders 
WHERE RowNumber BETWEEN 50 AND 60;

0

모든 SQL 서버 사용 :; tbl을 (SELECT ROW_NUMBER () over (order by (select 1))을 RowIndex로, 테이블에서 *)로 상위 10 * select tbl from RowIndex> = 10


-3
 SELECT * FROM users WHERE Id Between 15 and 25

MYSQ1에서와 같이 15에서 25까지 인쇄합니다.


2
사용자가 15에서 25 사이의 레코드를 삭제하면 어떻게됩니까?
Gökçer Gökdal
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.