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.