У меня есть большая проблема с SQL-оператором в Oracle. Я хочу выбрать Записи TOP 10, заказанные STORAGE_DB, которые не находятся в списке от другого избранного оператора.
Этот хорошо работает для всех записей:
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
Я получаю некоторые "случайные" Записи. Я думаю, потому что предел берет на месте перед порядком.
У кого-то есть хорошее решение? Другая проблема: Этот запрос является действительно медленным (10k + записи)
Вам нужно поместить текущий запрос в подзапрос, как показано ниже:
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
. Подробнее см. , .
Что касается плохой производительности, то это могло быть множество вещей, и это действительно должен быть отдельный вопрос. Однако есть одна очевидная вещь, которая может быть проблемой:
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.
Вы получаете явно случайный набор, потому что 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