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)



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.


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


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.


22

tratar

SELECT * FROM users FETCH NEXT 10 ROWS ONLY;

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.