Bagaimana cara melakukan top 1 di Oracle?

251

Bagaimana saya melakukan hal berikut?

select top 1 Fname from MyTbl

Dalam Oracle 11g ?

Emas
sumber
3
Bisakah Anda memberi tahu kami urutan yang Anda inginkan 'top 1'?
Andrew Wolfe
1
Pertama-tama Anda jangan pernah mengandalkan mesin DB untuk melakukan itu, selamanya. Jika Anda ingin mengetahui hal-hal seperti itu, masukkan sequencer. Ketika Anda melakukan itu dijamin bahwa mereka akan diberi nomor sesuai urutan mereka dimasukkan.
FlyingGuy
1
Materi yang sangat berguna tentang topik ini gunakan-the-index-luke.com/sql/partial-results/top-n-queries
Ilia Maskov

Jawaban:

257

Jika Anda ingin hanya baris yang dipilih pertama, Anda dapat:

select fname from MyTbl where rownum = 1

Anda juga dapat menggunakan fungsi analitik untuk memesan dan mengambil x atas:

select max(fname) over (rank() order by some_factor) from MyTbl
mcpeterson
sumber
54
Ini bagus jika Anda hanya ingin 1 baris dan tidak peduli yang mana. Jika Anda ingin baris tertentu, seperti catatan terbaru, Anda perlu melakukan pengurutan dalam subselect, seperti jawaban Vash. Oracle memberikan rownums sebelum penyortiran.
Scott Bailey
4
@Super, yup. itu betul. Dan Patrick, poin bagus menurut saya sintaksinya salah. Ini benar-benar harus menjadi penyimpan (dense_rank () terakhir ...)
mcpeterson
2
Perbedaan antara contoh pertama dan kedua adalah bahwa yang pertama memilih baris A (baris apa pun, tanpa urutan). Contoh kedua mendapatkan nilai baris pertama, tanpa melakukan kueri dalam pesanan (seperti contoh di bawah).
JulesLt
3
Sintaks dalam tidak benar di: pilih maks (nama)) lebih dari (peringkat () pesanan oleh some_factor) dari MyTbl
Stéphane Gerber
1
@ jclozano "bukan fungsi oracle yang sangat terkenal" - Dengan hormat, saya mohon berbeda. Ini penting karena "fungsi yang tidak terkenal" cenderung menyiratkan ketidakjelasan dan karenanya dapat menyarankan kita harus menghindari penggunaan. Ini tidak jelas, dan penggunaannya tidak harus dihindari.
Sepster
166
SELECT *
  FROM (SELECT * FROM MyTbl ORDER BY Fname )
 WHERE ROWNUM = 1;
Damian Leszczyński - Vash
sumber
8
Jawaban ini dengan benar mendapatkan baris TOP (memerintahkan hasil sebelum membatasi pada ROWNUM).
JulesLt
Jawaban ini bukan terjemahan yang tepat - kueri asli tidak memiliki ORDER OLEH, juga tidak mengembalikan semua kolom dalam tabel.
OMG Ponies
Saya berdiri dikoreksi (lihat di bawah). Akan beralih suara setelah waktu habis.
JulesLt
7
@OMGPonies ya. tapi mungkin itulah yang sebenarnya diinginkan kebanyakan orang yang mengunjungi laman ini melalui googling masalah mereka
NimChimpsky
4
Ini pasti harus menjadi jawaban yang menang di utas ini. Saya mungkin menambahkan catatan bahwa untuk top Xseseorang dapat mengubahnya keWHERE ROWNUM <= X
SomethingSomething
31

Dengan Oracle 12c (Juni 2013), Anda dapat menggunakannya seperti berikut ini.

SELECT * FROM   MYTABLE
--ORDER BY COLUMNNAME -OPTIONAL          
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
MSK
sumber
6
Perintah yang menarik, saya menggunakan 12c di sini dan OFFSET 0 ROWStampaknya tidak perlu, Anda dapat menggunakan FETCH NEXT 1 ROWS ONLYatau bahkan FETCH FIRST ROW ONLY, urutan oleh itu penting atau akan setara dengan hanya menggunakan a WHERE rownum = 1. Saya bahkan sudah mencobanya dalam instruksi BERLAKU LUAR dan berfungsi seperti fungsi TOP Ms-SQL di sana.
Rafael Merlin
Anda benar @RafaelMerlin. Setelah posting Anda, saya menyadari bahwa OFFSET 0 ROWS tidak diperlukan. Ini akan berguna ketika mengambil data antara X atas dan atas Y.
MSK
1
Contoh lainnya: oracle-base.com/articles/12c/…
FixFaier
Sejauh ini bagus, dengan poin penting yang hilang TIES. Lihat ini untuk kasus-kasus ketika ikatan terjadi untuk versi 12c +dan12c -
Barbaros Özhan
10

Anda bisa menggunakan ROW_NUMBER()dengan ORDER BYklausa dalam sub-kueri dan menggunakan kolom ini sebagai pengganti TOP N. Ini bisa dijelaskan selangkah demi selangkah.

Lihat tabel di bawah ini yang memiliki dua kolom NAMEdan DT_CREATED.

masukkan deskripsi gambar di sini

Jika Anda hanya perlu mengambil dua tanggal pertama terlepas dari NAME, Anda dapat menggunakan kueri di bawah ini. Logikanya telah ditulis di dalam kueri

-- The number of records can be specified in WHERE clause
SELECT RNO,NAME,DT_CREATED
FROM
(
    -- Generates numbers in a column in sequence in the order of date
    SELECT ROW_NUMBER() OVER (ORDER BY DT_CREATED) AS RNO,
    NAME,DT_CREATED
    FROM DEMOTOP
)TAB
WHERE RNO<3;

HASIL

masukkan deskripsi gambar di sini

Dalam beberapa situasi, kita perlu memilih TOP Nhasil masing-masing NAME. Dalam kasus seperti itu, kita dapat menggunakan PARTITION BYdengan ORDER BYklausa dalam sub-kueri. Lihat kueri di bawah ini.

-- The number of records can be specified in WHERE clause
SELECT RNO,NAME,DT_CREATED
FROM
(
  --Generates numbers in a column in sequence in the order of date for each NAME
    SELECT ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY DT_CREATED) AS RNO,
    NAME,DT_CREATED
    FROM DEMOTOP
)TAB
WHERE RNO<3;

HASIL

masukkan deskripsi gambar di sini

Sarath Avanavu
sumber
1
Menggunakan ROW_NUMBER () ... adalah solusi yang lebih benar daripada dalam jawaban topik Satu masalah dengan solusi ini (dan dengan varian max (bidang) juga) yang tidak dapat Anda lakukan seperti "pilih ... (pilih ROW_NUMBER () ...) untuk pembaruan ;"
Alexo Po.
Dan kadang-kadang sangat penting dalam PL / SQL (maaf, gagal mengedit komentar sebelumnya dalam batas 5 menit).
Alexo Po.
Dalam kasus seperti itu kita dapat menggunakan CTE seperti di bagian luar. Baik? @Alexo Po.
Sarath Avanavu
Saya pikir saya tidak mengerti Anda. untuk klausa pembaruan dapat digunakan ketika ROWID "mudah" diawetkan oleh Oracle. Jadi pengelompokan (dan pengelompokan karena penggunaan klausa analitik) menyembunyikan ROWID nyata dan baris tidak dapat dikunci. Dan kedua, CTE ( with (select ... ) as klausa) tidak mengubah apa pun untuk masalah ini, CTE hanya bertujuan membaca dan mendukung pertanyaan. Baik? @Sarath Avanavu
Alexo Po.
Perhatikan diri saya. Masalah dengan ROWID sebenarnya terjadi secara khusus karena kondisi RNO <3 , dalam hal ini nilai RNO tidak terhubung dengan ROWID sehingga Oracle tidak dapat mengunci baris.
Alexo Po.
9

Anda dapat melakukan sesuatu seperti

    SELECT *
      FROM (SELECT Fname FROM MyTbl ORDER BY Fname )
 WHERE rownum = 1;

Anda juga bisa menggunakan fungsi analitik RANK dan / atau DENSE_RANK , tetapi ROWNUM mungkin yang paling mudah.

Suman
sumber
1
dapatkah Anda membantu dengan beberapa contoh peringkat dll.
breakfreehg
9
select * from (
    select FName from MyTbl
)
where rownum <= 1;
ya
sumber
5

Menggunakan:

SELECT x.*
  FROM (SELECT fname 
          FROM MyTbl) x
 WHERE ROWNUM = 1

Jika menggunakan Oracle9i +, Anda dapat melihat menggunakan fungsi analitik seperti ROW_NUMBER () tetapi mereka tidak akan berkinerja sebaik ROWNUM .

OMG Ponies
sumber
1
Jawaban yang bagus tetapi mengandung kesalahan ketik kecil. Di mana Anda mengatakan Oracle9i + bukankah seharusnya 8i? download-west.oracle.com/docs/cd/A87860_01/doc/server.817/…
Ian Carpenter
@carp Minister: Benar, analitik tersedia dalam 8i - tidak dapat mengingat detailnya, tetapi analitik tidak benar-benar tersedia untuk umum hingga 9i.
OMG Ponies
Komentar kecil - Jawaban Vash di bawah ini mencakup ORDER OLEH pada permintaan dalam yang sangat penting jika Anda ingin nilai TOP dari fname, bukan 'pertama' (yang bisa berupa apa saja, kemungkinan besar baris pertama dimasukkan). Mungkin layak diedit?
JulesLt
@JulesLt: Permintaan yang diberikan oleh OP tidak termasuk ORDER OLEH, jadi ini adalah jawaban yang mewakili dan terjemahan yang tepat untuk sintaks Oracle.
OMG Ponies
Kesalahpahaman saya tentang sintaks SQL SERVER TOP (salah mengira bahwa itu mirip dengan PERTAMA dalam RANK, bukan ROWNUM). Terpilih.
JulesLt
3

Untuk memilih baris pertama dari sebuah tabel dan memilih satu baris dari sebuah tabel adalah dua tugas yang berbeda dan memerlukan kueri yang berbeda. Ada banyak cara yang memungkinkan untuk melakukannya. Empat di antaranya adalah:

Pertama

select  max(Fname) from MyTbl;

Kedua

select  min(Fname) from MyTbl;

Ketiga

select  Fname from MyTbl  where rownum = 1;

Keempat

select  max(Fname) from MyTbl where rowid=(select  max(rowid) from MyTbl)
Vikas Hardia
sumber
3

Saya memiliki masalah yang sama, dan saya dapat memperbaikinya dengan solusi ini:

select a.*, rownum 
from (select Fname from MyTbl order by Fname DESC) a
where
rownum = 1

Anda dapat memesan hasil Anda sebelum memiliki nilai pertama di atas.

Semoga berhasil

pengguna2607028
sumber