Oracle
クエリをMySQL limit
句を含むように動作させる方法はありますか?
MySQL
では、これを行うことができます。
select *
from sometable
order by name
limit 20,10
21行目から30行目までを取得します(最初の20行をスキップし、次の10行を指定します)。行はorder by
の後で選択されるので、実際にはアルファベット順で20番目の名前から始まります。
Oracle
では、人々が言及するのはrownum
疑似列だけですが、の前にorder by
が評価されます。
select *
from sometable
where rownum <= 10
order by name
名前順に並べられた10行のランダムなセットを返します。これは通常私が望むものではありません。オフセットを指定することもできません。
Oracle 12c R1(12.1)以降では、は行制限句 です。使い慣れたLIMIT
構文は使用しませんが、より多くのオプションを使用するとより効果的に作業を実行できます。あなたはここで 完全な構文を見つけることができます 。
元の質問に答えるために、これがクエリです:
SELECT *
FROM sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
(以前のバージョンのOracleについては、この質問の他の回答を参照してください)
以下の例は、リンク腐敗を防ぐために、 リンクされたページ から引用されています。
CREATE TABLE rownum_order_test (
val NUMBER
);
INSERT ALL
INTO rownum_order_test
SELECT level
FROM dual
CONNECT BY level <= 10;
COMMIT;
SELECT val
FROM rownum_order_test
ORDER BY val;
VAL
----------
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
20 rows selected.
N
行を取得するSELECT val
FROM rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS ONLY;
VAL
----------
10
10
9
9
8
5 rows selected.
N
の場合、最初のN
行を取得します番目 行に関係がある場合は、すべての関係のある行を取得しますSELECT val
FROM rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS WITH TIES;
VAL
----------
10
10
9
9
8
8
6 rows selected.
x
%行SELECT val
FROM rownum_order_test
ORDER BY val
FETCH FIRST 20 PERCENT ROWS ONLY;
VAL
----------
1
1
2
2
4 rows selected.
SELECT val
FROM rownum_order_test
ORDER BY val
OFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY;
VAL
----------
3
3
4
4
4 rows selected.
SELECT val
FROM rownum_order_test
ORDER BY val
OFFSET 4 ROWS FETCH NEXT 20 PERCENT ROWS ONLY;
VAL
----------
3
3
4
4
4 rows selected.
あなたはこのようなサブクエリを使うことができます
select *
from
( select *
from emp
order by sal desc )
where ROWNUM <= 5;
詳細については、Oracle/AskTomでROWNUMに関するトピック および結果を制限する も参照してください。
更新:下限と上限の両方で結果を制限するために、事情でもう少し肥大する
select * from
( select a.*, ROWNUM rnum from
( <your_query_goes_here, with order by> ) a
where ROWNUM <= :MAX_ROW_TO_FETCH )
where rnum >= :MIN_ROW_TO_FETCH;
(指定されたAskTom記事からコピー)
Update 2:Oracle 12c(12.1)以降では、行数を制限したりオフセットから開始するための構文があります。
SELECT *
FROM sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
他の例については この答え をご覧ください。ヒントをくれたKrumiaに感謝します。
私は以下の方法でパフォーマンステストを行いました。
select * from (
select a.*, ROWNUM rnum from (
<select statement with order by clause>
) a where rownum <= MAX_ROW
) where rnum >= MIN_ROW
select * from (
<select statement with order by clause>
) where myrow between MIN_ROW and MAX_ROW
select * from (
select statement, rownum as RN with order by clause
) where a.rn >= MIN_ROW and a.rn <= MAX_ROW
テーブルには1000万件のレコードがあり、ソートはインデックスのないdatetime行にあります。
最初の10行を選択すると
100,000から100,010までの行を選択します。
9,000,000〜9,000,010の行を選択します。
入れ子になったクエリが1つだけの分析ソリューション
SELECT * FROM
(
SELECT t.*, Row_Number() OVER (ORDER BY name) MyRow FROM sometable t
)
WHERE MyRow BETWEEN 10 AND 20;
Rank()
の代わりにRow_Number()
を使用することもできますが、nameの値が重複していると、予想よりも多くのレコードが返される可能性があります。
Oracle 12cの場合( SQLリファレンス の行制限句を参照)。
SELECT *
FROM sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
順序付きのページネーションクエリは、Oracleでは本当に扱いにくいです。
Oracleは、データベースがテーブルまたは一連の結合ビューから行を選択する順序を示す番号を返すROWNUM疑似列を提供します。
ROWNUMは多くの人を困らせる疑似列です。 ROWNUM値は、行に永続的に割り当てられるわけではありません(これはよくある誤解です)。 ROWNUM値が実際に割り当てられている場合は混乱するかもしれません。 ROWNUM値は、クエリの行フィルタ述語を渡した後に割り当てられますが、クエリ集計またはソートの前に割り当てられます。
さらに、ROWNUM値は割り当てられた後にのみ増加します。
これが、後続のクエリが行を返さない理由です。
select *
from (select *
from some_table
order by some_column)
where ROWNUM <= 4 and ROWNUM > 1;
照会結果の最初の行はROWNUM> 1述部を通過しないので、ROWNUMは2に増分しません。このため、ROWNUM値が1より大きくなることはなく、その結果、照会は行を戻しません。
正しく定義されたクエリは次のようになります。
select *
from (select *, ROWNUM rnum
from (select *
from skijump_results
order by points)
where ROWNUM <= 4)
where rnum > 1;
Vertabelo ブログのページネーションクエリについてもっと知りたい:
少ないSELECTステートメント。また、パフォーマンスが低下します。クレジットに:[email protected]
SELECT *
FROM (SELECT t.*,
rownum AS rn
FROM shhospede t) a
WHERE a.rn >= in_first
AND a.rn <= in_first;
Oracle 12Cを使用していない場合は、以下のようにTOP Nクエリを使用できます。
SELECT *
FROM
( SELECT rownum rnum
, a.*
FROM sometable a
ORDER BY name
)
WHERE rnum BETWEEN 10 AND 20;
次のようにwith句でfrom句を移動することもできます。
WITH b AS
( SELECT rownum rnum
, a.*
FROM sometable a ORDER BY name
)
SELECT * FROM b
WHERE rnum BETWEEN 10 AND 20;
ここでは、実際にはインラインビューを作成し、rownumの名前をrnumに変更しています。あなたはフィルタ基準としてメインクエリでrnumを使うことができます。
受け入れられた回答 の拡張として、Oracleは内部でROW_NUMBER/RANK
関数を使用します。 OFFSET FETCH
構文は構文シュガーです。
DBMS_UTILITY.EXPAND_SQL_TEXT
プロシージャを使用して確認できます。
サンプルの準備:
CREATE TABLE rownum_order_test (
val NUMBER
);
INSERT ALL
INTO rownum_order_test
SELECT level
FROM dual
CONNECT BY level <= 10;
COMMIT;
クエリ:
SELECT val
FROM rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS ONLY;
定期的です:
SELECT "A1"."VAL" "VAL"
FROM (SELECT "A2"."VAL" "VAL","A2"."VAL" "rowlimit_$_0",
ROW_NUMBER() OVER ( ORDER BY "A2"."VAL" DESC ) "rowlimit_$$_rownumber"
FROM "ROWNUM_ORDER_TEST" "A2") "A1"
WHERE "A1"."rowlimit_$$_rownumber"<=5 ORDER BY "A1"."rowlimit_$_0" DESC;
展開されたSQLテキストの取得:
declare
x VARCHAR2(1000);
begin
dbms_utility.expand_sql_text(
input_sql_text => '
SELECT val
FROM rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS ONLY',
output_sql_text => x);
dbms_output.put_line(x);
end;
/
WITH TIES
はRANK
として展開されます:
declare
x VARCHAR2(1000);
begin
dbms_utility.expand_sql_text(
input_sql_text => '
SELECT val
FROM rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS WITH TIES',
output_sql_text => x);
dbms_output.put_line(x);
end;
/
SELECT "A1"."VAL" "VAL"
FROM (SELECT "A2"."VAL" "VAL","A2"."VAL" "rowlimit_$_0",
RANK() OVER ( ORDER BY "A2"."VAL" DESC ) "rowlimit_$$_rank"
FROM "ROWNUM_ORDER_TEST" "A2") "A1"
WHERE "A1"."rowlimit_$$_rank"<=5 ORDER BY "A1"."rowlimit_$_0" DESC
およびオフセット:
declare
x VARCHAR2(1000);
begin
dbms_utility.expand_sql_text(
input_sql_text => '
SELECT val
FROM rownum_order_test
ORDER BY val
OFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY',
output_sql_text => x);
dbms_output.put_line(x);
end;
/
SELECT "A1"."VAL" "VAL"
FROM (SELECT "A2"."VAL" "VAL","A2"."VAL" "rowlimit_$_0",
ROW_NUMBER() OVER ( ORDER BY "A2"."VAL") "rowlimit_$$_rownumber"
FROM "ROWNUM_ORDER_TEST" "A2") "A1"
WHERE "A1"."rowlimit_$$_rownumber"<=CASE WHEN (4>=0) THEN FLOOR(TO_NUMBER(4))
ELSE 0 END +4 AND "A1"."rowlimit_$$_rownumber">4
ORDER BY "A1"."rowlimit_$_0"
select * FROM (SELECT
ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID,
FROM EMP ) EMP where ROWID=5
値よりも大きい
select * FROM (SELECT
ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID,
FROM EMP ) EMP where ROWID>5
値よりも少ない
select * FROM (SELECT
ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID,
FROM EMP ) EMP where ROWID=5
この記事 で説明したように、SQL:2008 Standardは次の構文を提供してSQL結果セットを制限します。
SELECT
title
FROM
post
ORDER BY
id DESC
FETCH FIRST 50 ROWS ONLY
バージョン12cより前のTop-Nレコードを取得するには、派生テーブルとROWNUM疑似列を使用する必要がありました。
SELECT *
FROM (
SELECT
title
FROM
post
ORDER BY
id DESC
)
WHERE ROWNUM <= 50
12cに対して検証されたOracle 1z0-047試験の準備を始めました。準備中に、 'FETCH FIRST'として知られる12cの拡張機能に出くわしました。いくつかのオプションがそれで利用可能です
- FETCH FIRST n ROWS ONLY
- OFFSET n ROWS FETCH NEXT N1 ROWS ONLY // leave the n rows and display next N1 rows
- n % rows via FETCH FIRST N PERCENT ROWS ONLY
例:
Select * from XYZ a
order by a.pqr
FETCH FIRST 10 ROWS ONLY
問合せによって戻される各行に対して、ROWNUM疑似列は、Oracleが表または一連の結合行から行を選択する順序を示す番号を返します。選択された最初の行のROWNUMは1、2番目の行は2、というようになります。
SELECT * FROM sometable1 so
WHERE so.id IN (
SELECT so2.id from sometable2 so2
WHERE ROWNUM <=5
)
AND ORDER BY so.somefield AND ROWNUM <= 100
私はこれをOracle
サーバー11.2.0.1.0
に実装しました