Oracle SELECT TOP 10 records

144

Saya memiliki masalah besar dengan Pernyataan SQL di Oracle. Saya ingin memilih TOP 10 Records yang dipesan oleh STORAGE_DB yang tidak ada dalam daftar dari pernyataan pilih lainnya.

Ini berfungsi dengan baik untuk semua catatan:

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') 

Tetapi ketika saya menambahkan

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

Saya mendapatkan semacam "acak" Records. Saya pikir karena batasnya terjadi sebelum pesanan.

Apakah seseorang memiliki solusi yang baik? Masalah lainnya: Permintaan ini benar-benar lambat (catatan 10k +)

opHASnoNAME
sumber

Jawaban:

199

Anda harus memasukkan kueri saat ini di subquery seperti di bawah ini:

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 menerapkan rownum pada hasilnya setelah dikembalikan.
Anda perlu memfilter hasilnya setelah dikembalikan, sehingga diperlukan subquery. Anda juga dapat menggunakan fungsi RANK () untuk mendapatkan hasil Top-N.

Untuk kinerja coba gunakan NOT EXISTSdi tempat NOT IN. Lihat ini untuk lebih lanjut.

Padmarag
sumber
BUKAN EXISTS tidak berfungsi dalam skenario ini (operator relasional tidak valid) APP_ID BUKAN ADA (SELEC ...)
opHASnoNAME
3
Beberapa orang mungkin mengatakan bahwa ini cenderung untuk mematikan orang ke Oracle.
MrBoJangles
2
Periksa FETCH NEXT N ROWS ONLYjawabannya di bawah ini.
Mohnish
@ Padmarag: Kapan rownum berlaku dalam kueri seperti ini - Pilih * dari SomeTable di mana someColumn = '123' dan rownum <= 3. Apakah setelah memilih hasil dari [Pilih * dari SomeTable di mana someColumn = '123']
Shirgill Farhan
55

Jika Anda menggunakan Oracle 12c, gunakan:

FETCH BERIKUTNYA N BARANG HANYA

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

Info lebih lanjut: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html

Volpato
sumber
2
ini emas dibandingkan dengan jawaban lain
aswzen
Saya setuju dengan aswzen
Austin Springer
1
Saya ingin memberikan jawaban ini 100 suara positif! Tapi sayang, saya hanya punya satu untuk penghargaan. Salah satunya!
eidylon
23

Sehubungan dengan kinerja yang buruk ada sejumlah hal yang bisa terjadi, dan itu benar-benar harus menjadi pertanyaan terpisah. Namun, ada satu hal yang jelas bisa menjadi masalah:

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

Jika HISTORY_DATE benar-benar adalah kolom tanggal dan jika memiliki indeks maka penulisan ulang ini akan berkinerja lebih baik:

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

Ini karena konversi tipe data menonaktifkan penggunaan indeks B-Tree.

APC
sumber
22

mencoba

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

Anda mendapatkan set yang tampaknya acak karena ROWNUM diterapkan sebelum ORDER BY. Jadi kueri Anda mengambil sepuluh baris pertama dan mengurutkannya.0 Untuk memilih sepuluh gaji teratas, Anda harus menggunakan fungsi analitik dalam subquery, lalu filter itu:

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