Oracle SELECT TOP 10 registros

144

Tengo un gran problema con una declaración SQL en Oracle. Quiero seleccionar los TOP 10 registros ordenados por STORAGE_DB que no están en una lista de otra declaración de selección.

Este funciona bien para todos los 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') 

Pero cuando estoy agregando

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

Estoy obteniendo algún tipo de registros "al azar". Creo que porque el límite tiene lugar antes de la orden.

¿Alguien tiene una buena solución? El otro problema: esta consulta es realmente lenta (10k + registros)

opHASnoNAME
fuente

Respuestas:

199

Deberá poner su consulta actual en la subconsulta de la siguiente manera:

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 al resultado después de que ha sido devuelto.
Debe filtrar el resultado después de que se haya devuelto, por lo que se requiere una subconsulta. También puede usar la función RANK () para obtener resultados Top-N.

Para el rendimiento, intente usar NOT EXISTSen lugar de NOT IN. Mira esto para más.

Padmarag
fuente
NOT EXISTS no funciona en este escenario (operador relacional no válido) APP_ID NOT EXISTS (SELEC ...)
opHASnoNAME el
3
Algunos pueden decir que esto puede apagar a las personas a Oracle.
MrBoJangles
2
Verifique la FETCH NEXT N ROWS ONLYrespuesta a continuación.
Mohnish
@Padmarag: ¿Cuándo se aplica un rownum en una consulta como esta? Seleccione * de SomeTable donde someColumn = '123' y rownum <= 3. ¿Es después de seleccionar los resultados de [Seleccionar * de SomeTable donde someColumn = '123']
Shirgill Farhan
55

Si está utilizando Oracle 12c, use:

FETCH SIGUIENTE N SOLO FILAS

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

Más información: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html

Volpato
fuente
2
esto es oro en comparación con otra respuesta
como el
Estoy de acuerdo con aswzen
Austin Springer
1
¡Quiero dar esta respuesta 100 votos a favor! Pero, por desgracia, solo tengo uno para premiar. Uno es!
eidylon
23

Con respecto al bajo rendimiento, hay muchas cosas que podrían ser, y realmente debería ser una pregunta separada. Sin embargo, hay una cosa obvia que podría ser un problema:

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

Si HISTORY_DATE realmente es una columna de fecha y si tiene un índice, esta reescritura funcionará mejor:

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

Esto se debe a que una conversión de tipo de datos deshabilita el uso de un índice B-Tree.

APC
fuente
22

tratar

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

Obtiene un conjunto aparentemente aleatorio porque ROWNUM se aplica antes de ORDER BY. Por lo tanto, su consulta toma las primeras diez filas y las ordena.0 Para seleccionar los diez salarios principales, debe usar una función analítica en una subconsulta y luego filtrar eso:

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