web-dev-qa-db-ja.com

Oracle SELECT TOP 10レコード

OracleのSQL文に大きな問題があります。他の選択ステートメントからのリストにないSTORAGE_DBによって順序付けられたトップ10レコードを選択したいです。

これはすべてのレコードに対してうまく機能します。

SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
      STORAGE_GB IS NOT NULL AND 
        APP_ID NOT IN (SELECT APP_ID
                       FROM HISTORY
                        WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009') 

しかし私が追加しているとき

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

私はある種の「ランダムな」レコードを入手しています。注文の前に限度があるためだと思います。

誰かが良い解決策を持っていますか?他の問題:この問い合わせは本当に遅いです(10k +レコード)

112
opHASnoNAME

以下のように現在のクエリをサブクエリに入れる必要があります。

SELECT * FROM (
  SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
    STORAGE_GB IS NOT NULL AND 
      APP_ID NOT IN (SELECT APP_ID FROM HISTORY WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') ='06.02.2009')
  ORDER BY STORAGE_GB DESC )
WHERE ROWNUM <= 10

Oracleは、返された結果に rownum を適用します。
結果が返された後で結果をフィルタ処理する必要があるため、副問合せが必要です。 Top-Nの結果を得るために RANK() 関数を使うこともできます。

パフォーマンスを向上させるために、NOT EXISTSの代わりにNOT INを使用してみてください。詳しくは this をご覧ください。

167
Padmarag

Oracle 12cを使用している場合は、次のコマンドを使用してください。

FETCH NEXTN行のみ

SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
    STORAGE_GB IS NOT NULL AND 
      APP_ID NOT IN (SELECT APP_ID FROM HISTORY WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') ='06.02.2009')
  ORDER BY STORAGE_GB DESC
FETCH NEXT 10 ROWS ONLY

詳細情報: http://docs.Oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html

25
Volpato

パフォーマンスの低さに関しては、考えられることはいくつもありますが、実際には別の質問にすべきです。しかし、問題になる可能性がある明白なことが1つあります。

WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009') 

HISTORY_DATEが実際に日付列であり、それにインデックスがある場合、この書き換えはより良く機能します。

WHERE HISTORY_DATE = TO_DATE ('06.02.2009', 'DD.MM.YYYY')  

これは、データ型変換によってB-Treeインデックスの使用が無効になるためです。

22
APC

やってみる

SELECT * FROM users FETCH NEXT 10 ROWS ONLY;
11
Shaaban

ROWNUMはORDER BYの前に適用されるため、見かけ上はランダムなセットになります。そのため、クエリは最初の10行を受け取り、それらをソートします。0上位10位の給与を選択するには、副問合せで分析関数を使用してから、それをフィルタ処理します。

 select * from 
     (select empno,
             ename,
             sal,
             row_number() over(order by sal desc nulls last) rnm
    from emp) 
 where rnm<=10
10
vijaya