SQLデータベーステーブルのn番目の行を選択するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/16568

質問

(理想的には) データベースに依存しない選択方法を学ぶことに興味があります。 nデータベーステーブルの 2 番目の行。次のデータベースのネイティブ機能を使用してこれをどのように実現できるかを見るのも興味深いでしょう。

  • 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 のクレジット: フィロス・アンサリのウェブログ

アップデート: 見る トロールズ・アービンの答え SQL標準について。 トロールズさん、引用できるリンクはありますか?

役に立ちましたか?

解決

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

このことや他のことについて話している本当に良いサイトは次のとおりです。 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 で動作します。

他のヒント

LIMIT / OFFSET PostgreSQL の構文 は:

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

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

どうやら SQL 標準は、クレイジーなウィンドウ関数以外の制限の問題については沈黙しており、それが人によって実装方法が異なる理由です。

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

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

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

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

構文:

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

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

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() をサポートしていない古いバージョンでも動作するはずです。

SQL Server で確認します。

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

これにより、emp テーブルの 10 番目の行が得られます。

1 つの小さな変更:n の代わりに n-1 を使用します。

select *
from thetable
limit n-1, 1

一部の回答の主張に反して、SQL 標準はこの問題に関して沈黙を守っているわけではありません。

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

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

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

オラクル:

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

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

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

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

これがあなたの混乱を素早く解決する方法です。

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 番目の最高金額のレコードを取得できます。フィールドとテーブル名を当てはめて解決策を考え出すことができます。

追加:

LIMIT n,1

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

たとえば、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 番を好きな数字に変更するだけです。

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

これは、私が最近 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);

しかし実際には、これらすべてはそもそも、優れたデータベース設計のための単なるお座敷テクニックではないでしょうか?このような機能が必要になったのは、簡単なレポートを作成するための単純な 1 回限りのクエリのためでした。実際の仕事では、このようなトリックを使用するとトラブルが発生します。特定の行を選択する必要がある場合は、連続した値を含む列を用意するだけで済みます。

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

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

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

Sybase SQL Anywhere の場合:

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

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

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
SELECT * FROM emp a
WHERE  n = (SELECT COUNT( _rowid)
              FROM emp b
             WHERE a. _rowid >= b. _rowid);
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

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 を入力してください。

これを実行する 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

私と同じように Caché を使用する場合のために、特別なことは何もありませんし、特別な機能もありません...

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

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

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

SELECT * FROM (                        
   SELECT RRN(FOO) AS RRN, FOO.*
   FROM FOO                         
   ORDER BY RRN(FOO)) BAR             
 WHERE BAR.RRN = recordnumber
select * from 
(select * from ordered order by order_id limit 100) x order by 
x.order_id desc limit 1;

まず昇順で並べ替えて上位 100 行を選択し、次に降順で並べ替えて最後の行を選択し、1 に制限します。ただし、これはデータに 2 回アクセスするため、非常にコストのかかるステートメントです。

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

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

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

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;
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top