Registros Oracle SELECT TOP 10

144

Eu tenho um grande problema com uma instrução SQL no Oracle. Desejo selecionar os 10 melhores registros ordenados por STORAGE_DB que não estão em uma lista de outra instrução de seleção.

Este funciona bem para todos os registros:

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 estou adicionando

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

Estou recebendo algum tipo de registro "aleatório". Eu acho que porque o limite ocorre antes do pedido.

Alguém tem uma boa solução? O outro problema: Esta consulta é muito lenta (10k + registros)

opHASnoNAME
fonte

Respostas:

199

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

O Oracle aplica o rownum ao resultado após o retorno.
Você precisa filtrar o resultado após o retorno, para que seja necessária uma subconsulta. Você também pode usar a função RANK () para obter os melhores resultados.

Para obter desempenho, tente usar NOT EXISTSno lugar de NOT IN. Veja isso para mais.

Padmarag
fonte
NOT EXISTS não está funcionando neste cenário (operador relacional inválido) APP_ID NOT EXISTS (SELEC ...)
opHASnoNAME
3
Alguns podem dizer que isso é capaz de desviar as pessoas para a Oracle.
MrBoJangles
2
Verifique a FETCH NEXT N ROWS ONLYresposta abaixo.
Mohnish
@ Padmarag: Quando um rownum se aplica a uma consulta como esta - selecione * de SomeTable em que someColumn = '123' e rownum <= 3. É depois de selecionar os resultados de [Select * from SomeTable where someColumn = '123']
Shirgill Farhan
55

Se você estiver usando o Oracle 12c, use:

BUSCAR PRÓXIMAS N LINHAS

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

Mais informações: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html

Volpato
fonte
2
isto é ouro em comparação com outra resposta
aswzen
Eu concordo com aswzen
Austin Springer
1
Quero dar a essa resposta 100 votos positivos! Mas, infelizmente, só tenho um para premiar. Um é esse!
eidylon
23

No que diz respeito ao fraco desempenho, pode haver várias coisas, e realmente deve ser uma pergunta separada. 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 for uma coluna de data e se tiver um índice, essa reescrita terá um desempenho melhor:

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

Isso ocorre porque uma conversão de tipo de dados desabilita o uso de um índice B-Tree.

APC
fonte
22

experimentar

SELECT * FROM users FETCH NEXT 10 ROWS ONLY;
Shaaban
fonte
11

Você obtém um conjunto aparentemente aleatório porque ROWNUM é aplicado antes do ORDER BY. Portanto, sua consulta pega as dez primeiras linhas e as classifica.0 Para selecionar os dez principais salários, você deve usar uma função analítica em uma subconsulta e filtrar isso:

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