2010-03-23 23 views
85

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

Esta 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 añadiendo

AND ROWNUM <= 10 
ORDER BY STORAGE_GB DESC 

estoy recibiendo algún tipo de registros "al azar". Creo que porque el límite toma lugar antes de la orden.

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

+0

Duplicado probable: http://stackoverflow.com/questions/2306744/oracle-sql-how-to-retrieve-highest-5-values-of-a-column – APC

Respuesta

142

Tendrá que 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 haya 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 EXISTS en lugar de NOT IN. Ver this para más.

+0

NOT EXISTS no funciona en este escenario (no válido) operador relacional) APP_ID NOT EXISTS (SELEC ...) – opHASnoNAME

22

En cuanto al bajo rendimiento, hay muchas cosas que podrían ser, y realmente debería ser una pregunta aparte. 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 entonces esta reescritura se obtienen mejores resultados:

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

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

10

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

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

Si está utilizando Oracle 12c, que puede utilizar:

fetch siguientes N sólo las 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

+1

Simple y al grano. FETCH NEXT 10 ROWS ONLY –

-4

puede simplemente use la Cláusula TOP

SELECCIONE LA PARTE SUPERIOR 10 * DE LA TABLA;

O

COLUMN_NAME (s) SELECT FROM nombre_tabla DONDE ROWNUM < = número;

+1

No en Oracle SQL ... – Zafi

2

try SELECCIONAR * FROM usuarios SIGUIENTE SIGUIENTE 10 FILAS SOLAMENTE;

+0

Solo funciona en Oracle 12c y posterior – Volpato

Cuestiones relacionadas