2010-03-23 28 views
85

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

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 

sto ottenere un certo genere dei primati "casuali". Penso che il limite si verifichi prima dell'ordine.

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

+0

Probabile duplicato: http://stackoverflow.com/questions/2306744/oracle-sql-how-to-retrieve-highest-5-values-of-a-column – APC

risposta

142

Avrete bisogno di mettere la vostra query corrente in subquery 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 si applica rownum al risultato dopo che è stato restituito.
È necessario filtrare il risultato dopo che è stato restituito, quindi è necessaria una sottoquery. Puoi anche utilizzare la funzione RANK() per ottenere risultati Top-N.

Per prestazioni, provare a utilizzare NOT EXISTS al posto di NOT IN. Vedi this per ulteriori informazioni.

+0

NON ESISTE non funziona in questo scenario (non valido operatore relazionale) APP_ID NON ESISTE (SELEC ...) – opHASnoNAME

22

Per quanto riguarda le prestazioni scadenti ci sono un certo numero di cose che potrebbe essere, e in realtà 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 data e se ha un indice quindi questa riscrittura si esibirà 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.

10

Si ottiene 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 i primi dieci stipendi si dovrebbe utilizzare una funzione analitica in una sottoquery, poi filtrare che:

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

Se si utilizza Oracle 12c, è possibile utilizzare:

Recupera soltanto righe successive N

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

+1

Semplice e preciso. FETCH NEXT SOLO 10 FILE –

-4

Puoi utilizzare semplicemente TOP Clause

SELEZIONARE TOP 10 * DA TABELLA;

O

SELEZIONE column_name (s) FROM nome_tabella WHERE ROWNUM < = numero;

+1

Non in Oracle SQL ... – Zafi

2

provare SELECT * FROM utenti FETCH NEXT 10 solo le righe;

+0

Funziona solo su Oracle 12c e versioni successive – Volpato

Problemi correlati