SQLデータベーステーブルのn番目の行を選択する方法


399

データベーステーブルからn番目の行を選択する、データベースにとらわれない方法を学習することに興味があります。また、次のデータベースのネイティブ機能を使用してこれを実現する方法も興味深いでしょう。

  • SQLサーバー
  • MySQL
  • PostgreSQL
  • SQLite
  • オラクル

現在、SQL Server 2005で次のようなことをしていますが、他のより不可知論的なアプローチに興味があります。

WITH Ordered AS (
SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS RowNumber, OrderID, OrderDate
FROM Orders)
SELECT *
FROM Ordered
WHERE RowNumber = 1000000

上記のSQLのクレジット:Firoz Ansariのウェブログ

更新: SQL標準に関するTroels Arvinの回答を参照してください。トロエル、私たちが引用できるリンクはありますか?


3
はい。ISO SQL標準に関する情報へのリンクは次のとおり
Troels Arvin

13
リレーションの定義では、テーブルの行には順序がないため、テーブルのN番目の行は選択できないことを指摘してください。選択できるのは、クエリ(の残りの部分)によって返される行セットのN番目の行です。これは、例と他のすべての回答が実行するものです。ほとんどの場合、これは単なる意味論かもしれませんが、それは質問の根本的な問題を指し示しています。を返す必要がある場合は、テーブルにOrderSequenceNo列をOrderNo N導入し、新しい注文の作成時に独立したシーケンスジェネレーターからそれを生成します。
Damir Sudarevic、2011年

2
オプションはSQL標準で定義されていますoffset x fetch first y rows only。現在(少なくとも)Postgres、Oracle12、DB2でサポートされています。
a_horse_with_no_name 2016年

回答:


349

標準のオプションの部分でこれを行う方法がありますが、多くのデータベースが独自の方法でサポートしています。

このことや他のことを語る本当に良いサイトはhttp://troels.arvin.dk/db/rdbms/#select-limitです。

基本的に、PostgreSQLとMySQLは非標準をサポートしています。

SELECT...
LIMIT y OFFSET x 

Oracle、DB2、およびMSSQLは、標準のウィンドウ関数をサポートしています。

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber,
    columns
  FROM tablename
) AS foo
WHERE rownumber <= n

(これらのDBを使用したことがないため、上記のリンクからコピーしただけです)

更新: PostgreSQL 8.4では、標準のウィンドウ関数がサポートされているため、2番目の例がPostgreSQLでも機能することを期待してください。

更新: 2018-09-15のバージョン3.25.0でSQLiteが追加したウィンドウ関数のサポートにより、両方のフォームがSQLiteでも機能します。


3
MySQLはOFFSETおよびLIMIT構文も使用します。FirebirdはFIRSTおよびSKIPキーワードを使用しますが、それらはSELECTの直後に配置されます。
Doug

7
それWHERE rownumber = nはn行目だけを取得することではないでしょうか?
スティーブベネット

MySQLはバージョン8以降のウィンドウ関数をサポートしています。バージョン10.2以降のMariaDB
Paul Spiegel

102

PostgreSQLは、SQL標準で定義されているウィンドウ関数をサポートしていますが、扱いにくいため、ほとんどの人が(非標準)LIMIT/をOFFSET使用しています。

SELECT
    *
FROM
    mytable
ORDER BY
    somefield
LIMIT 1 OFFSET 20;

この例では、21行目を選択します。OFFSET 20Postgresに最初の20レコードをスキップするように指示しています。ORDER BY句を指定しない場合、どのレコードが返されるかは保証されないため、ほとんど役に立ちません。


31

残りについてはわかりませんが、SQLiteとMySQLには「デフォルト」の行順序がないことを知っています。これらの2つの方言では、少なくとも、次のスニペットはthe_tableから15番目のエントリを取得し、追加された日付/時刻でソートします。

SELECT * FROM the_table ORDER BY added DESC LIMIT 1,15

(もちろん、DATETIMEフィールドを追加し、そのエントリが追加された日時に設定する必要があります...)


これは、インラインオフセット値でクエリを制限する最良の方法のようです。しかし、ここでは0,14を使用すべきではありませんか?1,15は最初の行を残します。
グラディエーター

15はどういう意味ですか?私は1が1つのレコードを取得するように言っているのを知っています。コンマは、私がチェックアウトした例で使用されていない1keydata.com/sql/sql-limit.html
committedandroider

1
実は、ここからphp.about.com/od/mysqlcommands/g/Limit_sql.htmあなたは15日のエントリを取得したい場合、あなたはLIMIT 14、1(0番目は、長さの1最初の要素でないだろう
committedandroiderの

SELECT * FROM the_table ORDER BYを追加する必要がありますDESC LIMIT 15,1を追加
JerryGoyal

25

SQL 2005以降には、この機能が組み込まれています。ROW_NUMBER()関数を使用します。<< Prev and Next >>スタイルのブラウジングを持つWebページに最適です。

構文:

SELECT
    *
FROM
    (
        SELECT
            ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum,
            *
        FROM
            Table_1
    ) sub
WHERE
    RowNum = 23

私はこの解決策を好むのは、それがより簡単に感じるからです。
FoxArc、

18

これは非常に非効率的ではないかと思いますが、私が試した小さなデータセットで機能する非常に単純なアプローチです。

select top 1 field
from table
where field in (select top 5 field from table order by field asc)
order by field desc

これは5番目のアイテムを取得し、2番目の上位数を変更して別のn番目のアイテムを取得します

SQLサーバーのみ(私は思う)が、ROW_NUMBER()をサポートしない古いバージョンで動作するはずです。


ROW_NUMBER()はSQL 2000では機能しないので、これを使用します(はい、SQL 2000にクライアントがあります)具体的には、「5」をループのイテレータ変数に置き換えて使用します。テーブルの各行を順番にコピーおよび変更します。たぶん、誰かがこのコメントを見て、これが役に立つと思うでしょう
逆に


14

SQL Serverでそれを確認します。

Select top 10 * From emp 
EXCEPT
Select top 9 * From emp

これで、empテーブルの10行目が表示されます。


この質問への回答はすでにここにあります。正しくないと思われる回答を削除してください。両方の回答が正しいと思われる場合は、両方の回答を1か所に投稿してください
SpringLearner

11

いくつかの回答が主張することに反して、SQL標準はこの主題に関して沈黙していません。

SQL:2003以降、「ウィンドウ関数」を使用して行をスキップし、結果セットを制限できるようになりました。

SQL:2008では、少しシンプルなアプローチが追加され、
OFFSET skip ROWS FETCH FIRST n ROWS ONLY

個人的には、SQL:2008の追加が本当に必要だったとは思わないので、もし私がISOだったら、もうかなり大きな標準には入れなかっただろう。


しかし、標準があることは素晴らしいことですが、私のような人々の生活を楽にし、標準的な方法で
何か

7

以前はMSSQL 2000で作業していたときに、「トリプルフリップ」と呼ばれる処理を行いました。

編集済み

DECLARE @InnerPageSize int
DECLARE @OuterPageSize int
DECLARE @Count int

SELECT @Count = COUNT(<column>) FROM <TABLE>
SET @InnerPageSize = @PageNum * @PageSize
SET @OuterPageSize = @Count - ((@PageNum - 1) * @PageSize)

IF (@OuterPageSize < 0)
    SET @OuterPageSize = 0
ELSE IF (@OuterPageSize > @PageSize)
    SET @OuterPageSize = @PageSize

DECLARE @sql NVARCHAR(8000)

SET @sql = 'SELECT * FROM
(
    SELECT TOP ' + CAST(@OuterPageSize AS nvarchar(5)) + ' * FROM
    (
        SELECT TOP ' + CAST(@InnerPageSize AS nvarchar(5)) + ' * FROM <TABLE> ORDER BY <column> ASC
    ) AS t1 ORDER BY <column> DESC
) AS t2 ORDER BY <column> ASC'

PRINT @sql
EXECUTE sp_executesql @sql

エレガントではなく、速くもありませんでしたが、うまくいきました。


25行あり、10行のページサイズの3ページ目、つまり21〜25行が必要だとします。最も内側のクエリは、上位30行(行1〜25)を取得します。中央のクエリは、最後の10行(行25〜16)を取得します。外部クエリはそれらを並べ替え、行16〜25を返します。行21〜25が必要な場合、これは明らかに誤りです。
Bill Karwin、2011

現在、中間ページが必要な場合は機能しません。25行あり、2番目のページ、つまり行11〜20が必要だとします。内部クエリは、上位2 * 10 = 20行、または行1-20を取得します。真ん中のクエリは最後の15行を取得します:25-((2-1)* 10)= 15、行20-6になります。最後のクエリは順序を逆にして、行6〜20を返します。行の合計数が目的のページサイズの倍数でない限り、この手法は機能しません。
Bill Karwin、2011

おそらく最良の結論は、残りのMS SQL Server 2000インスタンスをアップグレードする必要があるということです。:-)それはほぼ2012年であり、この問題は長年にわたってより良い方法で解決されています!
Bill Karwin、2011

@Bill Karwin:計算のIF / ELSE IF下のブロックに注意してください。1 OuterPageSizeページと2ページでは、OuterPageSize値が10に戻ります。3ページ(行21〜25)では、計算は正しく5を返し、4ページ以上では、計算の否定的な結果は0に置き換えられます(ただし、その時点で空のデータ行をすぐに返す方がおそらく速いだけです)。
アダムV

ああ、わかりました。さて、今日のMS SQL Server 2000の使用は問題に値しないと私の意見を支持します。
Bill Karwin、2012年

6

SQLサーバー


上からn番目のレコードを選択

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

下からn番目のレコードを選択

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID DESC) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

5

Oracle:

select * from (select foo from bar order by foo) where ROWNUM = x

1
where ROWNUM = xOracle DBでx = 1に対してのみ機能します。つまりwhere ROWNUM = 2、行は返されません。
AFF

5

Oracle 12cでは、次のOFFSET..FETCH..ROWS オプションを使用できます。ORDER BY

たとえば、上から3番目のレコードを取得するには:

SELECT * 
FROM   sometable
ORDER BY column_name
OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY;

4

ここにあなたの混乱の速い解決があります。

SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1

ここでは、N = 0を入力することで最後の行を取得し、N = 1を入力して最後の行を取得し、N = 3を入力して最後の行を取得することができます。

これはインタビューで非常によくある質問で、これは非常に単純な質問です。

さらに、金額、ID、または数値の並べ替え順序が必要な場合は、MySQLのCAST関数でuよりも優先される場合があります。

SELECT DISTINCT (`amount`) FROM cart ORDER BY CAST( `amount` AS SIGNED ) DESC LIMIT 4 , 1

ここでは、N = 4と入力することで、CARTテーブルから5番目の最終レコードの最高金額を取得できます。あなたはあなたのフィールドとテーブル名を適合させ、解決策を考え出すことができます。



3

たとえば、MSSQLで10行ごとに選択する場合は、次を使用できます。

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY ColumnName1 ASC) AS rownumber, ColumnName1, ColumnName2
  FROM TableName
) AS foo
WHERE rownumber % 10 = 0

MODを取り、ここで番号10を任意の番号に変更します。


3

SQL Serverの場合、行番号で移動する一般的な方法は次のとおりです。

SET ROWCOUNT @row --@row = the row number you wish to work on.

例えば:

set rowcount 20   --sets row to 20th row

select meat, cheese from dbo.sandwich --select columns from table at 20th row

set rowcount 0   --sets rowcount back to all rows

これにより、20行目の情報が返されます。後から必ず行数0を入力してください。


2

LIMIT n、1は、MS SQL Serverでは機能しません。それは、その構文をサポートしない唯一の主要なデータベースについてだと思います。公平を期すために、それはSQL標準の一部ではありませんが、広くサポートされているはずなのでサポートする必要があります。SQLサーバー以外のすべてにおいて、LIMITはうまく機能します。SQLサーバーについては、エレガントなソリューションを見つけることができませんでした。


1
Oracle、DB2を除いて、世界中のほぼすべてのエンタープライズレベルデータベース。PostgreSQLは、LIMITキーワードをサポートする唯一のエンタープライズ対応データベースです。これは主に、オープンソースであるため、ACIDを無視するMySQL群衆がアプローチできる必要があるためです。
デビッド

3
@AlexDこの「回答」は、Stackoverflowの昔、コメントが実装される前に投稿されました。私はこれを別の回答へのコメントとして投稿したでしょうが、当時、コメントは存在しませんでした。
Kibbee 2012

2

これは、動的ページング/ソートを可能にするOracle用に最近書いたsprocの汎用バージョンです-HTH

-- p_LowerBound = first row # in the returned set; if second page of 10 rows,
--                this would be 11 (-1 for unbounded/not set)
-- p_UpperBound = last row # in the returned set; if second page of 10 rows,
--                this would be 20 (-1 for unbounded/not set)

OPEN o_Cursor FOR
SELECT * FROM (
SELECT
    Column1,
    Column2
    rownum AS rn
FROM
(
    SELECT
        tbl.Column1,
        tbl.column2
    FROM MyTable tbl
    WHERE
        tbl.Column1 = p_PKParam OR
        tbl.Column1 = -1
    ORDER BY
        DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 1, Column1, 'X'),'X'),
        DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 1, Column1, 'X'),'X') DESC,
        DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate),
        DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate) DESC
))
WHERE
    (rn >= p_lowerBound OR p_lowerBound = -1) AND
    (rn <= p_upperBound OR p_upperBound = -1);

2

しかし、実際には、これらすべてが、そもそも優れたデータベース設計のためのパーラートリックだけではないのでしょうか。数回、このような機能が必要になったのは、簡単な1回限りのクエリですばやくレポートを作成するためでした。実際の作業では、このようなトリックを使用すると問題が発生します。特定の行を選択する必要がある場合は、順次値を持つ列を用意し、それで処理を完了します。


2

SQLサーバーの場合、以下は指定されたテーブルの最初の行を返します。

declare @rowNumber int = 1;
    select TOP(@rowNumber) * from [dbo].[someTable];
EXCEPT
    select TOP(@rowNumber - 1) * from [dbo].[someTable];

あなたはこのようなもので値をループすることができます:

WHILE @constVar > 0
BEGIN
    declare @rowNumber int = @consVar;
       select TOP(@rowNumber) * from [dbo].[someTable];
    EXCEPT
       select TOP(@rowNumber - 1) * from [dbo].[someTable];  

       SET @constVar = @constVar - 1;    
END;

1

Sybase SQL Anywhereの場合:

SELECT TOP 1 START AT n * from table ORDER BY whatever

ORDER BYを忘れないでください。そうしないと意味がありません。


1

T-SQL-テーブルからN番目のRecordNumberを選択する

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from TableName) T where T.Rno = RecordNumber

Where  RecordNumber --> Record Number to Select
       TableName --> To be Replaced with your Table Name

たとえば、テーブルEmployeeから5番目のレコードを選択するには、クエリは次のようになります。

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5

1
SELECT * FROM emp a
WHERE  n = (SELECT COUNT( _rowid)
              FROM emp b
             WHERE a. _rowid >= b. _rowid);

1
SELECT
    top 1 *
FROM
    table_name
WHERE
    column_name IN (
        SELECT
            top N column_name
        FROM
            TABLE
        ORDER BY
            column_name
    )
ORDER BY
    column_name DESC

このクエリは、N番目の行を見つけるために作成しました。このクエリの例は次のようになります

SELECT
    top 1 *
FROM
    Employee
WHERE
    emp_id IN (
        SELECT
            top 7 emp_id
        FROM
            Employee
        ORDER BY
            emp_id
    )
ORDER BY
    emp_id DESC

0

あなたがこれを実行しているSQLエンジンを見つけることができるとは信じられない...

WITH sentence AS
(SELECT 
    stuff,
    row = ROW_NUMBER() OVER (ORDER BY Id)
FROM 
    SentenceType
    )
SELECT
    sen.stuff
FROM sentence sen
WHERE sen.row = (ABS(CHECKSUM(NEWID())) % 100) + 1

0

私のようにCachéを使用する場合、特別な機能や特別な機能はありません...

SELECT TOP 1 * FROM (
  SELECT TOP n * FROM <table>
  ORDER BY ID Desc
)
ORDER BY ID ASC

信頼できるID列または日付スタンプ列があると仮定します。


0

これは、DB2 SQLでこれを行う方法です。RRN(相対レコード番号)は、O / Sによってテーブル内に格納されていると思います。

SELECT * FROM (                        
   SELECT RRN(FOO) AS RRN, FOO.*
   FROM FOO                         
   ORDER BY RRN(FOO)) BAR             
 WHERE BAR.RRN = recordnumber

0
select * from 
(select * from ordered order by order_id limit 100) x order by 
x.order_id desc limit 1;

最初に昇順で上位100行を選択し、次に降順で最後の行を選択して1に制限します。ただし、データに2回アクセスするため、これは非常に負荷の高いステートメントです。


0

効率的にするには、1)0からデータベースレコードの数よりも1少ない乱数を生成し、2)その位置で行を選択できるようにする必要があるようです。残念ながら、データベースによって、乱数ジェネレーターが異なり、結果セット内の位置で行を選択する方法も異なります。通常、スキップする行の数と必要な行の数を指定しますが、データベースごとに異なる方法で行われます。SQLiteで私のために働く何かはここにあります:

select * 
from Table 
limit abs(random()) % (select count(*) from Words), 1;

制限句でサブクエリを使用できるかどうかに依存します(SQLiteではLIMIT <スキップするスキップ>、<取得する>)テーブル内のレコード数の選択は、データベースの一部であり、特に効率的である必要がありますメタデータですが、それはデータベースの実装に依存します。また、クエリがN番目のレコードを取得する前に実際に結果セットを構築するかどうかはわかりませんが、そうする必要がないことを願っています。「order by」句を指定していないことに注意してください。インデックスを持つ主キーのようなものを「並べ替え」た方がよい場合があります。データベースが結果セットを構築せずにデータベース自体からN番目のレコードを取得できない場合は、インデックスからN番目のレコードを取得する方が高速です。 。


0

この記事でSQLサーバーについて見た最も適切な答え

WITH myTableWithRows AS (
    SELECT (ROW_NUMBER() OVER (ORDER BY myTable.SomeField)) as row,*
    FROM myTable)
SELECT * FROM myTableWithRows WHERE row = 3
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.