Oracle SELECT TOP 10レコード


144

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

なんらかの「ランダム」レコードを取得しています。制限は注文の前に行われるためだと思います。

誰かが良い解決策を持っていますか?その他の問題:このクエリは非常に遅い(1万レコード以上)



回答:


199

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

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を適用します。
結果が返された後、結果をフィルタリングする必要があるため、サブクエリが必要です。RANK()関数を使用して、トップNの結果を取得することもできます。

パフォーマンスについてNOT EXISTSは、の代わりに使用してみてくださいNOT IN。詳しくはこちらをご覧ください。


NOT EXISTSはこのシナリオでは機能しません(無効な関係演算子)APP_ID NOT EXISTS(SELEC ...)
opHASnoNAME

3
一部の人々は、これが人々をオラクルにオフにする傾向があると言うかもしれません。
MrBoJangles

2
FETCH NEXT N ROWS ONLY以下の答えを確認してください。
モニッシュ、

@Padmarag:このようなクエリにrownumが適用される場合-someColumn = '123'およびrownum <= 3のSomeTableから*を選択します。[Select * from SomeTable where someColumn = '123']から結果を選択した後ですか
Shirgill Farhan

55

Oracle 12cを使用している場合は、以下を使用します。

次のN行のみフェッチ

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


2
これは他の回答と比較して金です
aswzen

私はaswzenに同意します
オースティンスプリンガー

1
この答えを100票にしたいと思います。しかし、悲しいかな、私が授与できるのは1つだけです。1つです。
eidylon

23

パフォーマンスの低下に関しては、いくつかの可能性がありますが、実際には別の質問でなければなりません。ただし、問題になる可能性のある明らかなことが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ツリーインデックスの使用が無効になるためです。



11

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.