SQL ServerのLIMITおよびOFFSETと同等ですか?


172

PostgreSQLには、結果セットの非常に簡単なページ分割を可能にするLimitOffsetキーワードがあります。

SQL Serverの同等の構文は何ですか?


SQL Server 2012の場合、この機能は簡単な方法で実装されます。私の回答を
Somnath Muluk 2013年

この質問をお寄せいただきありがとうございます。MySQLからMsSQLへの移行を余儀なくされています:(
tempcke

オフセットを使用して、SQL Serverの次のステートメントをORDER BY句でフェッチできます。試してみてくださいyoutu.be/EqHkAiiBwPc
Amresh Kumar Singh

回答:


139

LIMITis 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

ここでの利点は、ページングオプションを変更する(またはユーザーが変更できるようにする)場合のオフセットと制限のパラメーター化です。

注:@Offsetパラメータではなく、通常のゼロベースのインデックスよりも、このための1ベースのインデックスを使用する必要があります。


22
今は古い。SQL Server 2012以降はオフセット/
フェッチを

31
@JoelCoehoorn古くない。過去にmysqlのみを使用していたSLQサーバー2008を使用してプロジェクトに割り当てられました...
クトゥルフ

これはかなり良いですが、少し調整する必要がありますWHERE RowNum >= (@Offset + 1)
Eric Herlitz

5
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified。MSSQL2008 R2。
ポール、

2
@Aaronaught 20万Table件のレコードがある場合、最初にすべて取得してから制限を適用しますか このクエリは効率的ですか?
Jigar、2016年

231

この機能はSQL Server 2012で簡単になりました。これはSQL Server 2012以降で機能します。

SQL Serverで11〜20行を選択するには、オフセットで制限します。

SELECT email FROM emailTable 
WHERE user_id=3
ORDER BY Id
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY;
  • OFFSET:スキップされた行の数
  • NEXT:必要な次の行数

リファレンス:https : //docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017


4
SQL_CALC_FOUND_ROWSこれを使用する場合の同等物はありますか?
Petah 2015年

1
@Petah @@ Rowcountはあなたに私が思うことを与える
Rob Sedgwick

GOTCHA:CTE内からこれを使用することはできません。メインクエリで使用する必要があります。行を決定して高価な計算を実行し、必要なものをスキップ/取得するのではなく、返される行の量(ページ分割)を制限し、高額な計算を10行程度に制限したいと考えていました。@Aaronaughtの回答は、CTE内の行を制限する必要がある場合に有効です。
デレックディーン2017

@Somnath Mulukこのオフセットとフェッチは、1000000のオフセットでデータ量が多い例の場合、多くの時間がかかります。これをどのように処理できますか?
Saroj Shrestha 2018年

1
@SarojShrestha:これはオフセットとフェッチの問題ではありません。ここで、テーブルのアーキテクチャを再確認する必要があります。テーブルのパーティション化、データ行、および異なる列タイプと合計テーブルサイズを検討し、定期的に必要でない場合はいくつかの行をアーカイブすることを検討し、サーバーの仕様を確認してください。
Somnath Muluk、2018年

23
select top {LIMIT HERE} * from (
      select *, ROW_NUMBER() over (order by {ORDER FIELD}) as r_n_n 
      from {YOUR TABLES} where {OTHER OPTIONAL FILTERS}
) xx where r_n_n >={OFFSET HERE}

注意: このソリューションは、SQL Server 2005以降でのみ機能しますROW_NUMBER()


私はこのクエリをしばらく使用してきましたが、非常に効果的です。「xx」が何を表しているのか気になりますか?
アーブリー2014年

サブクエリには名前が必要です。私はそれを使用していないので、そこにxxを置くだけです
jorgeu

2
xxは単なるテーブルエイリアスです。あなたが言ったなら、それは少し明確かもしれませんAS xx
コンクリートギャネット

誰もがこのクエリで左結合を行う方法を知っていますか?
ドレニル

12

これを実現するには、共通テーブル式でROW_NUMBERを使用できます。

;WITH My_CTE AS
(
     SELECT
          col1,
          col2,
          ROW_NUMBER() OVER(ORDER BY col1) AS row_number
     FROM
          My_Table
     WHERE
          <<<whatever>>>
)
SELECT
     col1,
     col2
FROM
     My_CTE
WHERE
     row_number BETWEEN @start_row AND @end_row

4

私にとって、OFFSETとFETCHの併用は遅いため、TOPとOFFSETの組み合わせを使用しました(この方が高速でした)。

SELECT TOP 20 * FROM (SELECT columname1, columname2 FROM tablename
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS) aliasname

注:同じクエリでTOPとOFFSETを一緒に使用すると、次のようになります。

SELECT TOP 20 columname1, columname2 FROM tablename
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS

次にエラーが発生するため、TOPとOFFSETを一緒に使用するには、サブクエリでそれを分離する必要があります。

SELECT DISTINCTを使用する必要がある場合、クエリは次のようになります。

SELECT TOP 20 FROM (SELECT DISTINCT columname1, columname2
    WHERE <conditions...> ORDER BY columname1 OFFSET 100 ROWS) aliasname

注: DISTINCTでSELECT ROW_NUMBERを使用しても機能しませんでした。


1
「TOPはOFFSETと同じクエリまたはサブクエリでは使用できません。」と表示されます。
MichaelRushton

あなたは正しい@MichaelRushtonであり、同じクエリまたは同じサブクエリで使用できないため、サブクエリを使用してそれを分離する必要があります。したがって、SQLのような場合、SQLを次のようSELECT TOP 20 id FROM table1 where id > 10 order by date OFFSET 20 rowsに変換する必要がありますSELECT TOP 20 * FROM (SELECT id FROM table1 where id > 10 order by date OFFSET 20 ROWS) t1。回答を編集します。ありがとう、すみません、私の英語。
sebasdev 2017年

2

別のサンプル:

declare @limit int 
declare @offset int 
set @offset = 2;
set @limit = 20;
declare @count int
declare @idxini int 
declare @idxfim int 
select @idxfim = @offset * @limit
select @idxini = @idxfim - (@limit-1);
WITH paging AS
    (
        SELECT 
             ROW_NUMBER() OVER (order by object_id) AS rowid, *
        FROM 
            sys.objects 
    )
select *
    from 
        (select COUNT(1) as rowqtd from paging) qtd, 
            paging 
    where 
        rowid between @idxini and @idxfim
    order by 
        rowid;

15
マイクロソフトの悪意のある表現を削除しました。ここでは聖戦については議論しないでください。主観的ではない方法で質問に答えてください。
Earlz 2011

2

あり、ここで、SQL 2011でこの機能について語って誰か、その悲しいが、「OFFSET / FETCH」彼らは少し異なったキーワードを選択するが、そのないスタンダール[OK]を。


2

Aaronaughtのソリューションにわずかなバリエーションを追加して、私は通常、ページ番号(@PageNum)とページサイズ(@PageSize)をパラメーター化します。このように、各ページクリックイベントは、構成可能なページサイズとともに、要求されたページ番号を送信するだけです。

begin
    with My_CTE  as
    (
         SELECT col1,
              ROW_NUMBER() OVER(ORDER BY col1) AS row_number
     FROM
          My_Table
     WHERE
          <<<whatever>>>
    )
    select * from My_CTE
            WHERE RowNum BETWEEN (@PageNum - 1) * (@PageSize + 1) 
                              AND @PageNum * @PageSize

end

2

私が作ることができる最も近いものは

select * FROM( SELECT *, ROW_NUMBER() over (ORDER BY ID ) as ct from [db].[dbo].[table] ) sub where ct > fromNumber  and ct <= toNumber

私はそれに似ていると思います select * from [db].[dbo].[table] LIMIT 0, 10


1
select top (@TakeCount) * --FETCH NEXT
from(
    Select  ROW_NUMBER() OVER (order by StartDate) AS rowid,*
    From YourTable
)A
where Rowid>@SkipCount --OFFSET

1
@nombre_row :nombre ligne par page  
@page:numero de la page

//--------------code sql---------------

declare  @page int,@nombre_row int;
    set @page='2';
    set @nombre_row=5;
    SELECT  *
FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY etudiant_ID ) AS RowNum, *
      FROM      etudiant

    ) AS RowConstrainedResult
WHERE   RowNum >= ((@page-1)*@nombre_row)+1
    AND RowNum < ((@page)*@nombre_row)+1
ORDER BY RowNum

1

まだ誰もこのコードを提供していないので:

SELECT TOP @limit f1, f2, f3...
FROM t1
WHERE c1 = v1, c2 > v2...
AND
    t1.id NOT IN
        (SELECT TOP @offset id
         FROM t1
         WHERE c1 = v1, c2 > v2...
         ORDER BY o1, o2...)
ORDER BY o1, o2...

重要なポイント:

  • ORDER BYは同一でなければなりません
  • @limit 取得する結果の数で置き換えることができ、
  • @offset スキップする結果の数です
  • 以前のソリューションの方が効率的かもしれないため、パフォーマンスを比較してください
  • このソリューションは句whereorder by句を複製し、それらが同期していない場合に誤った結果を提供します
  • 一方、それorder byが必要な場合は明示的にあります

1
-- @RowsPerPage  can be a fixed number and @PageNumber number can be passed 
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 2

SELECT *

FROM MemberEmployeeData

ORDER BY EmployeeNumber

OFFSET @PageNumber*@RowsPerPage ROWS

FETCH NEXT 10 ROWS ONLY

1

具体的にはSQL-SERVERの場合、さまざまな方法でそれを実現できます。実際の例として、ここではCustomerテーブルを取り上げました。

例1:「SET ROWCOUNT」を使用する

SET ROWCOUNT 10
SELECT CustomerID, CompanyName from Customers
ORDER BY CompanyName

すべての行を返すには、ROWCOUNTを0に設定します

SET ROWCOUNT 0  
SELECT CustomerID, CompanyName from Customers
    ORDER BY CompanyName

例2:「ROW_NUMBERおよびOVER」を使用

With Cust AS
( SELECT CustomerID, CompanyName,
ROW_NUMBER() OVER (order by CompanyName) as RowNumber 
FROM Customers )
select *
from Cust
Where RowNumber Between 0 and 10

例3: "OFFSET and FETCH"を使用するが、これを使用する場合 "ORDER BY"は必須

SELECT CustomerID, CompanyName FROM Customers
ORDER BY CompanyName
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY

これがお役に立てば幸いです。



-1

なぜなら、私はこのスクリプトをより多くの回数テストします。ページごとに100万レコードずつページ付けを行うと100レコードずつ速くなります。私のPCではこのスクリプトを0秒実行しますが、mysqlと比較すると、独自の制限とオフセットがあり、結果を得るには約4.5秒かかります。

誰かがRow_Number()を常に特定のフィールドでソートすることを理解できないことがあります。シーケンスの行のみを定義する必要がある場合は、次を使用する必要があります。

ROW_NUMBER()OVER(ORDER BY(SELECT NULL))

SELECT TOP {LIMIT} * FROM (
      SELECT TOP {LIMIT} + {OFFSET} ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS ROW_NO,*
      FROM  {TABLE_NAME}
) XX WHERE ROW_NO > {OFFSET}

説明:

  • {LIMIT}:各ページのレコード数
  • {OFFSET}:スキップレコードの数

2
このコードは問題を解決する可能性がありますが、これが問題を解決する方法と理由の説明含めると、投稿の品質が向上し、おそらくより多くの投票が得られます。あなたが今尋ねている人だけでなく、あなたが将来の読者のための質問に答えていることを忘れないでください。回答を編集して説明を追加し、適用される制限と前提を示してください。
ブライアン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.