2010-03-23 4 views
85

У меня большая проблема с SQL-заявлением в Oracle. Я хочу выбрать TOP 10 записей, заказанных STORAGE_DB, которые не входят в список из другого оператора select.Oracle SELECT TOP 10 записей

Это один работает для всех записей:

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') 

Но когда я добавляю

AND ROWNUM <= 10 
ORDER BY STORAGE_GB DESC 

Я получаю своего рода "случайных" Records. Я думаю, потому что предел принимает место перед порядком.

У кого-то есть хорошее решение? Другая проблема: Этот запрос действительно медленный (10k + записей)

+0

Возможный дубликат: http://stackoverflow.com/questions/2306744/oracle-sql-how-to-retrieve-highest-5-values-of-a-column – APC

ответ

142

Вам нужно перевести текущий запрос в подзапрос, как показано ниже:

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 применяет rownum к результату после того, как он был возвращен.
Вам нужно отфильтровать результат после его возврата, поэтому требуется подзапрос. Вы также можете использовать функцию RANK(), чтобы получить результаты Top-N.

Для повышения эффективности попробуйте использовать NOT EXISTS вместо NOT IN. См. this для получения дополнительной информации.

+0

NOT EXISTS не работает в этом сценарии (недействительный реляционный оператор) APP_ID NOT EXISTS (SELEC ...) – opHASnoNAME

22

Что касается плохих характеристик, то есть любое количество вещей, которые могут быть, и это действительно должен быть отдельный вопрос. Однако, есть одна очевидная вещь, что может быть проблема:

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

Если HISTORY_DATE действительно столбец даты и если он имеет индекс, то это переписывание будет работать лучше:

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

Это происходит потому, что преобразование типа данных отключает использование индекса B-Tree.

10

Вы получаете случайно выбранный набор, потому что ROWNUM применяется до ORDER BY. Таким образом, ваш запрос занимает первые десять строк и сортирует их.0 Для того, чтобы выбрать десять лучших зарплаты вы должны использовать аналитическую функцию в подзапрос, затем процеживают, что:

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

Если вы используете Oracle 12c, вы можете использовать:

принести только следующие N строк

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 

Подробнее: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html

+1

Простой и понятный. FETCH NEXT 10 ROWS ONLY –

-4

Вы можете просто используйте пункт TOP

ВЫБЕРИТЕ TOP 10 * FROM TABLE;

Или

ВЫБОР имя_столбца (ы) FROM table_name WHERE ROWNUM < = число;

+1

Не в oracle SQL ... – Zafi

2

try SELECT * FROM пользователей FETCH NEXT 10 ROWS ONLY;

+0

Работает только с Oracle 12c и более поздними версиями – Volpato