Oracle SELECT TOP 10 записей
Вопрос
У меня большая проблема с оператором SQL в Oracle.Я хочу выбрать ТОП-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
Я получаю какие-то "случайные" записи.Я думаю потому, что лимит действует еще до заказа.
Есть ли у кого-нибудь хорошее решение?Другая проблема:Этот запрос очень медленный (более 10 тыс. записей)
Решение
Вам нужно будет поместить текущий запрос в подзапрос, как показано ниже:
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 применяет число строк к результату после его возврата.
Вам необходимо отфильтровать результат после его возврата, поэтому требуется подзапрос.Вы также можете использовать КЛАССИФИЦИРОВАТЬ() функция для получения результатов Top-N.
Для производительности попробуйте использовать NOT EXISTS
на месте NOT IN
.Видеть этот для большего.
Другие советы
Если вы используете Oracle 12c, используйте:
ВЫБРАТЬ СЛЕДУЮЩИЙ Н ТОЛЬКО РЯДЫ
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
Что касается плохой производительности, то это может быть по-разному, и это действительно должен быть отдельный вопрос.Однако есть одна очевидная вещь, которая может стать проблемой:
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-дерева.
пытаться
SELECT * FROM users FETCH NEXT 10 ROWS ONLY;
Вы получаете явно случайный набор, поскольку ROWNUM применяется перед ORDER BY.Итак, ваш запрос берет первые десять строк и сортирует их. Чтобы выбрать десять самых высоких зарплат, вам следует использовать аналитическую функцию в подзапросе, а затем отфильтровать ее:
select * from
(select empno,
ename,
sal,
row_number() over(order by sal desc nulls last) rnm
from emp)
where rnm<=10