Oracle SELECT TOP 10 records

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

Questa 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 aggiungo

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

Sto ottenendo una specie di "record casuale". Penso perché il limite prende posto prima dell'ordine.

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

Soluzione

Avrai bisogno di mettere la tua query attuale in subquery come segue:


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 
Commentari (4)

Per quanto riguarda le scarse prestazioni, ci sono un certo numero di cose che potrebbero essere, e dovrebbe davvero 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, allora questa riscrittura funzionerà meglio:

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

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

Commentari (0)

Si ottiene un insieme apparentemente casuale perché ROWNUM è applicato prima dell'ORDER BY. Quindi la tua query prende le prime dieci righe e le ordina.0 Per selezionare i primi dieci stipendi dovresti usare una funzione analitica in una sottoquery, quindi filtrare quella:


 select * from 
     (select empno,
             ename,
             sal,
             row_number() over(order by sal desc nulls last) rnm
    from emp) 
 where rnm
Commentari (0)