Oracle SELECT TOP 10 record


144

Ho un grosso problema con un'istruzione SQL in Oracle. Voglio selezionare i 10 record TOP ordinati da STORAGE_DB che non sono in un elenco da un'altra istruzione select.

Questo funziona bene per tutti i record:

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

Ma quando sto aggiungendo

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

Ricevo una specie di dischi "casuali". Penso perché il limite ha luogo prima dell'ordine.

Qualcuno ha una buona soluzione? L'altro problema: questa query è davvero lenta (10k + record)



Risposte:


199

Dovrai inserire la query corrente nella sottoquery come di seguito:

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 applica il rownum al risultato dopo che è stato restituito.
È necessario filtrare il risultato dopo che è stato restituito, quindi è necessaria una sottoquery. È inoltre possibile utilizzare la funzione RANK () per ottenere risultati Top-N.

Per prestazioni, prova a utilizzare NOT EXISTSal posto di NOT IN. Vedi questo per di più.


NOT EXISTS non funziona in questo scenario (operatore relazionale non valido) APP_ID NOT EXISTS (SELEC ...)
opHASnoNAME

3
Alcuni potrebbero dire che questo è adatto a spegnere le persone su Oracle.
MrBoJangles,

2
Controlla la FETCH NEXT N ROWS ONLYrisposta qui sotto.
Mohnish,

@Padmarag: quando un rownum si applica in una query come questa - Seleziona * da SomeTable dove someColumn = '123' e rownum <= 3. È dopo aver selezionato i risultati da [Seleziona * da SomeTable dove someColumn = '123']
Shirgill Farhan,

55

Se si utilizza Oracle 12c, utilizzare:

FACCIA SUCCESSIVO SOLO N RIGHE

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

Maggiori informazioni: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html


2
questo è oro rispetto ad altra risposta
aswzen

Concordo con aswzen
Austin Springer l'

1
Voglio dare questa risposta 100 voti! Ma ahimè, ne ho solo uno da premiare. Uno è!
eidylon,

23

Per quanto riguarda le scarse prestazioni, ci sono molte cose che potrebbero essere e dovrebbe essere una domanda separata. Tuttavia, c'è una cosa ovvia che potrebbe essere un problema:

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

Se HISTORY_DATE è davvero una colonna di date e se ha un indice, questa riscrittura funzionerà meglio:

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

Questo perché una conversione del tipo di dati disabilita l'uso di un indice B-Tree.


22

provare

SELECT * FROM users FETCH NEXT 10 ROWS ONLY;

11

Ottieni un set apparentemente casuale perché ROWNUM viene applicato prima di ORDER BY. Quindi la tua query prende le prime dieci righe e le ordina.0 Per selezionare le prime dieci retribuzioni dovresti usare una funzione analitica in una sottoquery, quindi filtrare che:

 select * from 
     (select empno,
             ename,
             sal,
             row_number() over(order by sal desc nulls last) rnm
    from emp) 
 where rnm<=10
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.