Eu tenho um grande problema com uma Declaração SQL no Oracle. Eu quero selecionar os TOP 10 Records ordenados por STORAGE_DB que estão't em uma lista de uma outra instrução selecionada.
Este aqui funciona bem para todos os registos:
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')
Mas quando eu estou a adicionar
AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC
I'estou recebendo algum tipo de "aleatório" Registros. Acho que porque o limite é anterior ao pedido.
Alguém tem uma boa solução? O outro problema: Esta consulta é muito lenta (10k+ registos).
Você'precisará colocar sua consulta atual na subconsulta como abaixo :
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 aplica rownum ao resultado após ter sido retornado.
Você precisa filtrar o resultado após ele ter sido retornado, então uma subquisição é necessária. Você também pode usar a função RANK() para obter resultados Top-N.
Para desempenho tente utilizar NÃO EXISTE' no lugar de
NÃO IN'. Veja isto para mais informações.
No que diz respeito ao mau desempenho, há uma série de coisas que poderiam ser, e realmente deveria ser uma questão à parte. No entanto, há uma coisa óbvia que pode ser um problema:
WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009')
Se HISTORY_DATE é realmente uma coluna de datas e se tiver um índice, então esta reescrita terá um melhor desempenho:
WHERE HISTORY_DATE = TO_DATE ('06.02.2009', 'DD.MM.YYYY')
Isto porque uma conversão tipo datatype desabilita o uso de um índice B-Tree.
Você recebe um conjunto aparentemente aleatório porque o ROWNUM é aplicado antes do ORDER BY. Então sua consulta pega as primeiras dez linhas e as ordena.0 Para selecionar os dez salários mais altos você deve usar uma função analítica em uma subconsulta, depois filtrar isso:
select * from
(select empno,
ename,
sal,
row_number() over(order by sal desc nulls last) rnm
from emp)
where rnm<=10