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)
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 <= 10
Oracle applica rownum al risultato dopo che è stato restituito.
Avete bisogno di filtrare il risultato dopo che è stato restituito, quindi è necessaria una subquery. Potete anche usare la funzione RANK() per ottenere i risultati Top-N.
E' possibile utilizzare la funzione "RANK()" per ottenere i risultati migliori;
Per le prestazioni prova a usare NOT EXISTS
al posto di NOT IN
. Vedi this per saperne di più.
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.
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<=10