Come faccio a fare la top 1 in Oracle?


251

Come posso fare quanto segue?

select top 1 Fname from MyTbl

In Oracle 11g ?


Dai


3
Puoi dirci l'ordine in base al quale desideri "top 1"?
Andrew Wolfe,

1
Prima di tutto non dovresti mai fare affidamento sul motore DB per farlo, mai. Se vuoi sapere cose del genere, inserisci un sequencer. Quando lo fai, è garantito che saranno numerati nell'ordine in cui sono stati inseriti.
FlyingGuy

1
Materiale molto utile su questo argomento use-the-index-luke.com/sql/partial-results/top-n-queries
Ilia Maskov

Risposte:


257

Se vuoi solo una prima riga selezionata, puoi:

select fname from MyTbl where rownum = 1

Puoi anche usare le funzioni analitiche per ordinare e prendere la prima x:

select max(fname) over (rank() order by some_factor) from MyTbl

54
Questo è buono se vuoi solo 1 riga e non ti interessa quale. Se desideri righe specifiche, come il record più recente, devi eseguire l'ordinamento in una sottoselezione, come la risposta di Vash. Oracle assegna i rown prima dell'ordinamento.
Scott Bailey,

4
@Scott yup. è corretto. E Patrick, buon punto, penso che la sintassi non sia corretta su questo. Dovrebbe davvero essere un ricordo (dense_rank () last ...)
mcpeterson

2
La differenza tra il primo e il secondo esempio è che il primo seleziona una riga (qualsiasi riga, senza ordine). Il secondo esempio ottiene il valore della prima riga, senza eseguire una query interna dell'ordine (come negli esempi seguenti).
JulesLt

3
La sintassi non è corretta in: seleziona max (fname) over (rank () order by some_factor) da MyTbl
Stéphane Gerber

1
@jclozano "non è una funzionalità molto nota dell'oracolo" - Rispetto, mi permetto di dissentire. Ciò è importante perché "funzionalità non ben note" tende a implicare oscurità e quindi potrebbe suggerire che dovremmo evitare di utilizzarlo. Questo non è oscuro e il suo uso non dovrebbe essere evitato.
Settembre

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

8
Questa risposta ottiene correttamente la riga TOP (ordina i risultati prima di limitare su ROWNUM).
JulesLt

Questa risposta non è una traduzione esatta: la query originale non ha un ORDER BY, né restituisce tutte le colonne nella tabella.
OMG Pony

Sono corretto (vedi sotto). Passerà i voti una volta scaduto il tempo.
JulesLt

7
@OMGPonies sì. ma è probabilmente quello che la maggior parte della gente vuole davvero che venga su questa pagina
cercando su Google il

4
Questa sicuramente deve essere la risposta vincente in questa discussione. Potrei aggiungere una nota che per top Xuno può cambiarlo inWHERE ROWNUM <= X
SomethingSomething

31

Con Oracle 12c (giugno 2013), puoi usarlo come segue.

SELECT * FROM   MYTABLE
--ORDER BY COLUMNNAME -OPTIONAL          
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY

6
Comando interessante, sto usando 12c qui e OFFSET 0 ROWSapparentemente non è necessario, puoi usare FETCH NEXT 1 ROWS ONLYo anche FETCH FIRST ROW ONLY, l'ordine da è importante o sarà equivalente al solo utilizzo di a WHERE rownum = 1. L'ho anche provato in un'istruzione OUTER APPLY e ha funzionato come la funzione TOP di MS-SQL lì.
Rafael Merlin,

Hai ragione @RafaelMerlin. Dopo il tuo post ho riconosciuto che OFFSET 0 ROWS non è necessario. Sarebbe utile quando si recuperano i dati tra la X superiore e la Y superiore.
MSK


Fin qui tutto bene, con un importante punto mancante che è TIES. Fare riferimento questo per i casi in cui i legami si verificano per la versione 12c +e12c -
Barbaros Özhan

10

È possibile utilizzare ROW_NUMBER()con una ORDER BYclausola nella query secondaria e utilizzare questa colonna in sostituzione di TOP N. Questo può essere spiegato passo dopo passo.

Vedi la tabella sotto che ha due colonne NAMEe DT_CREATED.

inserisci qui la descrizione dell'immagine

Se è necessario prendere solo le prime due date indipendentemente da NAME, è possibile utilizzare la query seguente. La logica è stata scritta all'interno della query

-- 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;

RISULTATO

inserisci qui la descrizione dell'immagine

In alcune situazioni, dobbiamo selezionare i TOP Nrisultati rispettivamente per ciascuno NAME. In tal caso, possiamo utilizzare PARTITION BYuna ORDER BYclausola in una query secondaria. Fare riferimento alla query seguente.

-- 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;

RISULTATO

inserisci qui la descrizione dell'immagine


1
L'uso di ROW_NUMBER () ... è la soluzione più corretta rispetto alla risposta dell'argomento. Un problema con questa soluzione (e anche con la variante max (field)) che non puoi fare cose come "select ... (select ROW_NUMBER () ...) per l'aggiornamento ;"
Alexo Po.

Ed a volte è molto importante in PL / SQL (scusate, non è stato possibile modificare il commento precedente nel limite di 5 minuti).
Alexo Po.

In tal caso possiamo usare CTE come nella parte esterna. Destra? @Alexo Po.
Sarath Avanavu,

Penso di non capirti. per la clausola di aggiornamento può essere utilizzata quando ROWID è "facilmente" conservato da Oracle. Quindi il raggruppamento (e il raggruppamento a causa dell'uso della clausola analitica) nasconde il vero ROWID e le righe non possono essere bloccate. E in secondo luogo, CTE ( with (select ... ) as clausola) non cambia nulla in questo problema, CTE mira solo a leggere e supportare le query. Destra? @Sarath Avanavu
Alexo Po.

Nota su me stesso. Il problema con ROWID in realtà si verifica in modo specifico a causa della condizione in cui RNO <3 , in questo caso il valore di RNO non è collegato a ROWID, pertanto Oracle non può bloccare le righe.
Alexo Po.

9

Puoi fare qualcosa del genere

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

È inoltre possibile utilizzare le funzioni analitiche RANK e / o DENSE_RANK , ma ROWNUM è probabilmente il più semplice.


1
potete per favore aiutarmi con qualche esempio di grado ecc.
colazione del

9
select * from (
    select FName from MyTbl
)
where rownum <= 1;

5

Uso:

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

Se si utilizza Oracle9i +, è possibile utilizzare le funzioni analitiche come ROW_NUMBER () ma non funzioneranno come ROWNUM .


1
Bella risposta ma contiene un piccolo errore di battitura. Dove dici Oracle9i + non dovrebbe essere 8i? download-west.oracle.com/docs/cd/A87860_01/doc/server.817/…
Ian Carpenter

@carpenteri: Vero, i dati analitici erano disponibili in 8i - non ricordo i dettagli di, ma i dati analitici non erano realmente disponibili al pubblico fino al 9i.
OMG Pony

Piccolo commento - La risposta di Vash di seguito include un ORDER BY sulla query interna che è fondamentale se si desidera il valore TOP di fname, anziché "primo" (che può essere qualsiasi cosa, molto probabilmente la prima riga inserita). Potrebbe valere una modifica?
JulesLt

@JulesLt: la query fornita dall'OP non include un ORDER BY, quindi questa è la risposta che rappresenta e la traduzione esatta della sintassi Oracle.
OMG Pony

Il mio malinteso sulla sintassi di SQL SERVER TOP (erroneamente presunto che fosse simile a FIRST in RANK, non a ROWNUM). Votato.
JulesLt

3

Per selezionare la prima riga da una tabella e selezionare una riga da una tabella sono due attività diverse e è necessaria una query diversa. Ci sono molti modi possibili per farlo. Quattro di loro sono:

Primo

select  max(Fname) from MyTbl;

Secondo

select  min(Fname) from MyTbl;

Terzo

select  Fname from MyTbl  where rownum = 1;

Il quarto

select  max(Fname) from MyTbl where rowid=(select  max(rowid) from MyTbl)

3

Ho avuto lo stesso problema e posso risolverlo con questa soluzione:

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

Puoi ordinare il tuo risultato prima di avere il primo valore in cima.

In bocca al lupo

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.