448

データベーステーブルから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 の Weblog

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

4

33 に答える 33

378

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

これやその他のことについて話している本当に良いサイトは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 でも機能することを期待してください。

更新: SQLite は、2018 年 9 月 15 日にバージョン 3.25.0 でウィンドウ関数のサポートを追加したため、両方のフォームが SQLite でも機能します。

于 2008-08-19T19:22:15.100 に答える
118

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

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

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

于 2008-08-19T17:31:23.653 に答える
33

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

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

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

于 2008-08-19T17:20:33.410 に答える
26

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
于 2009-07-09T15:00:46.973 に答える
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() をサポートしていない古いバージョンでも動作するはずです。

于 2008-08-19T17:28:55.017 に答える
16

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

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

SQL:2008 では、もう少し単純なアプローチが追加されました。
OFFSET skip ROWS FETCH FIRST n ROWS ONLY

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

于 2008-09-03T22:39:36.883 に答える
15

1 つの小さな変更: n の代わりに n-1。

select *
from thetable
limit n-1, 1
于 2008-08-19T19:25:43.797 に答える
9

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
于 2014-02-19T04:17:16.883 に答える
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

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

于 2008-08-19T17:33:44.320 に答える
5

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

たとえば、上から 3 番目のレコードを取得するには、次のようにします。

SELECT * 
FROM   sometable
ORDER BY column_name
OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY;
于 2018-02-05T12:43:42.547 に答える
4

オラクル:

select * from (select foo from bar order by foo) where ROWNUM = x
于 2008-08-19T18:51:29.623 に答える
4

これがあなたの混乱の迅速な解決策です。

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

ここでは、N=0 を埋めることで最後の行、N=1 を埋めることで 2 番目の最後、N=3 を埋めることで最後の 4 番目の行などを得ることができます。

これは面接で非常によくある質問で、非常に簡単です。

さらに、金額、ID、または数値ソート順序が必要な場合は、MySQL の CAST 関数を使用できます。

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

ここで N = 4 を満たすことで、CART テーブルから 5 番目に最後の最高額のレコードを取得できます。フィールドとテーブル名を合わせて、解決策を考え出すことができます。

于 2012-05-17T09:29:27.093 に答える
3

追加:

LIMIT n,1

これにより、結果 n から始まる 1 つの結果に結果が制限されます。

于 2008-08-19T17:14:05.420 に答える
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 行目の情報が返されます。その後、rowcount 0 を必ず入れてください。

于 2009-06-22T17:00:08.453 に答える
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 を任意の番号に変更します。

于 2011-12-30T08:41:20.107 に答える
2

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

于 2008-08-19T19:06:57.580 に答える
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);
于 2008-08-19T17:19:01.540 に答える
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
于 2015-01-29T09:09:46.747 に答える
1

LIMIT n,1 は MS SQL Server では機能しません。その構文をサポートしていない唯一の主要なデータベースだと思います。公平を期すために、SQL 標準の一部ではありませんが、広くサポートされているため、そうすべきです。SQL サーバーの LIMIT 以外のすべてでうまく機能します。SQL サーバーについては、洗練された解決策を見つけることができませんでした。

于 2008-08-19T17:18:06.440 に答える
1

Sybase SQL Anywhere の場合:

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

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

于 2008-08-19T19:06:59.903 に答える
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

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

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5
于 2010-11-19T19:02:35.750 に答える
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
于 2009-03-06T13:30:06.187 に答える
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
于 2016-11-18T15:12:02.223 に答える