SQL Serverでの制限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()を含むすべてのソリューションの問題は、どの列を保持するかが事前にわからず、結合があり、結合されたテーブルの列名が同じである場合、「列「xxx」が複数回指定されました。」これは、最初に聞こえるほど一般的ではありません。私はDapperを使用しており、すべてのテーブルにId列があります。Dapperはそれを分割してマップするので、名前を変更したくありませんが、SELECT * FROM([元のクエリ])エイリアスを使用できません。私はまだ解決策を見つけていません!
Steve Owen、

回答:


104

このLIMIT句は標準SQLの一部ではありません。MySQL、PostgreSQL、SQLiteによるSQLのベンダー拡張としてサポートされています。

他のブランドのデータベースにも同様の機能(TOPMicrosoft SQL Serverなど)がある場合がありますが、これらが常に同じように機能するとは限りません。

TOPMicrosoft 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を指定する必要がありますが、MySqlおよびSQLiteは、LIMIT 5,5を使用する場合にORDER BYを必要としません
Tomas Kubes

4
@ qub1n-MySQL 、その場合にどの行が返されるかを保証しません
マーティン・スミス

3
を使用するoffset必要がありますか、またはその行を省略できますか(オフセットが不要であると想定)。
Cullub


クエリの例は正常に実行されますが、次のようにテーブル名とcolによる順序を次のように変更すると、SELECT * FROM DimProduct ORDER BY ProductKey OFFSET 5 ROWS FETCH NEXT 5 ROWS 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の回答の方が投票数が多く、実行計画をこのアプローチと比較した後、このソリューションの方が速く動作することがわかりました。
厳しい

10

SQL Server 2012+を使用している場合、Martin Smithの回答に投票し、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標準のアプローチです。LIMIT


@ジョエル:ROW_NUMBER()がORDER BYから出てくる方法で行に番号を付けることができない理由を説明できますか?なぜ「OVER(ORDER BY名)」が必須なのかといつも思っていましたが、それには正当な理由があると思います。あるいは、少なくとも理由。
Tomalak 2009年

3
というのも、order by句のない注文はありません。サーバーがレコードを利用できる順序を取得します。これは、クエリ要求ごとに変わる可能性があります。
Joel Coehoorn、2009年

1
@marcgg:MicrosoftがLIMITの実装を計画しているという兆候は読んだことがありません。そのような計画があったとしても、クローズドソースのベンダーは機能を事前に発表しない傾向があります。これは確かに役立つ機能ですが、コードを考えると、実装するのにどれだけの作業が必要かはわかりません。
ビルカーウィン、

3
ORDER BY句で繰り返したくない場合は、元の列のセットではなくROW_NUMBER()エイリアスを使用します。
ピーターラドッキア2009年

2
@Tomalak:SQL Serverに関する限り、ROW_NUMBER()の計算に使用される順序は、結果セットの順序とはまったく関係ありません。そのため、個別に指定する必要があります。
LukeH、2009年

6

これはどう?

SET ROWCOUNT 10 

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

最初の20行の最後の10行が表示されます。欠点の1つは順序が逆になることですが、少なくとも覚えるのは簡単です。


6
テーブルに14行しかない場合はどうなりますか?行14から5までを取得します。これは、LIMIT 10 OFFSET 10によって返される行とは異なります(行14から11までにする必要があります)。
ビルカーウィン、

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 as(SELECT ROW_NUMBER()over(order by(select 1))as RowIndex、* from table)select top 10 * from tbl where RowIndex> = 10


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

MYSQlの制限のように15から25まで印刷します


2
ユーザーが15〜25のレコードを削除した場合はどうなりますか?
GökçerGökdal
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.