Как ограничить количество строк, возвращаемых запросом Oracle после сортировки?
Вопрос: Как сделать так, чтобы запрос в Oracle работал аналогично оператору LIMIT в MySQL?
В MySQL я могу использовать следующий запрос:
select *
from sometable
order by name
limit 20,10
Этот запрос позволяет получить строки с 21-й по 30-ю (пропуская первые 20), причем строки выбираются после сортировки по order by
, так что фактически выборка начинается с 20-го имени в алфавитном порядке.
В Oracle же чаще всего упоминается псевдоколонка rownum
, но она оценивается до order by
, поэтому следующий запрос:
select *
from sometable
where rownum <= 10
order by name
возвращает произвольный набор из десяти строк, отсортированных по имени, что редко является желаемым результатом. Кроме того, не предусмотрена возможность указания смещения (offset).
Есть ли способ в Oracle сделать запросы с аналогичной функциональностью, как в MySQL с использованием limit
?
5 ответ(ов)
При проведении тестирования производительности для различных подходов к выборке данных, я использовал следующие три метода:
Asktom
select * from (
select a.*, ROWNUM rnum from (
<select statement with order by clause>
) a where rownum <= MAX_ROW
) where rnum >= MIN_ROW
Аналитический
select * from (
<select statement with order by clause>
) where myrow between MIN_ROW and MAX_ROW
Короткий альтернатива
select * from (
select statement, rownum as RN with order by clause
) where a.rn >= MIN_ROW and a.rn <= MAX_ROW
Результаты
Таблица содержала 10 миллионов записей, сортировка производилась по неиндексируемому полю типа datetime.
- План выполнения показал одинаковое значение для всех трёх запросов (323168).
- Однако лидером стал метод AskTom, за которым следовал аналитический метод.
Время выбора первых 10 строк составило:
- AskTom: 28-30 секунд
- Аналитический: 33-37 секунд
- Короткий альтернативный: 110-140 секунд
При выборе строк между 100,000 и 100,010:
- AskTom: 60 секунд
- Аналитический: 100 секунд
При выборе строк между 9,000,000 и 9,000,010:
- AskTom: 130 секунд
- Аналитический: 150 секунд
Таким образом, метод AskTom продемонстрировал наилучшие результаты по времени выполнения в сравнении с остальными подходами.
В данном случае можно использовать аналитическое решение с единственным вложенным запросом. Ваш запрос может выглядеть следующим образом:
SELECT * FROM
(
SELECT t.*, Row_Number() OVER (ORDER BY name) AS MyRow FROM sometable t
) AS subquery
WHERE MyRow BETWEEN 10 AND 20;
При этом стоит отметить, что функцию Rank()
можно заменить на Row_Number()
, но будьте осторожны: если в вашем наборе данных есть дубликаты значений в столбце name
, Rank()
может вернуть больше записей, чем вы ожидаете, так как она присваивает одинаковый ранг для одинаковых значений. В таком случае лучше использовать Row_Number()
, которая гарантирует уникальность назначаемых номеров строк.
В версии 21c вы можете просто применить ограничение, используя следующий запрос:
SELECT * FROM course WHERE ROWNUM <= 10;
Этот запрос вернет первые 10 записей из таблицы course
.
Вы начали подготовку к экзамену Oracle 1z0-047, который соответствует версии 12c, и столкнулись с улучшением данной версии, известным как 'FETCH FIRST'. Эта функция позволяет ограничивать количество извлекаемых строк по вашему усмотрению.
Существует несколько опций для использования:
FETCH FIRST n ROWS ONLY
— выбирает только первые n строк.OFFSET n ROWS FETCH NEXT N1 ROWS ONLY
— пропускает n строк и отображает следующие N1 строк.FETCH FIRST N PERCENT ROWS ONLY
— возвращает n процентов строк.
Пример использования:
SELECT * FROM XYZ a
ORDER BY a.pqr
FETCH FIRST 10 ROWS ONLY;
Это позволяет удобно управлять выводом данных и сокращать объем результатов выборки. Если у вас есть дополнительные вопросы или требуется помощь с другой частью подготовки, не стесняйтесь задавать!
В Oracle, псевдоколонка ROWNUM возвращает номер, который указывает порядок выбора строки из таблицы или набора присоединенных строк. Первая выбранная строка имеет ROWNUM равный 1, вторая - 2 и так далее.
В приведенном вами запросе есть несколько нюансов, на которые стоит обратить внимание. Вот пример того, как можно исправить ваш запрос:
SELECT *
FROM sometable1 so
WHERE so.id IN (
SELECT so2.id
FROM sometable2 so2
WHERE ROWNUM <= 5
)
AND ROWNUM <= 100
ORDER BY so.somefield;
Обратите внимание, что оператор ORDER BY
должен находиться в конце запроса, и условие AND ROWNUM <= 100
также должно располагаться перед ORDER BY
, чтобы корректно ограничить количество возвращаемых строк.
Однако, если вы хотите получить первые 100 строк на основе определенного порядка, вам может понадобиться использовать подзапрос. Например, вы можете сделать что-то вроде следующего:
SELECT *
FROM (
SELECT *
FROM sometable1 so
WHERE so.id IN (
SELECT so2.id
FROM sometable2 so2
WHERE ROWNUM <= 5
)
ORDER BY so.somefield
)
WHERE ROWNUM <= 100;
Этот подход обеспечит правильное применение сортировки перед применением ограничения по количеству строк.
Как конкатенировать текст из нескольких строк в одну строку в SQL Server
Как вывести список таблиц в файле базы данных SQLite, открытом с помощью ATTACH?
Обновление данных в одной таблице из другой на основе совпадения ID
Выбрать первую строку в каждой группе GROUP BY?
Как вывести сырой SQL-запрос в виде строки из билдера запросов?