13

Как ограничить количество строк, возвращаемых запросом Oracle после сортировки?

9

Вопрос: Как сделать так, чтобы запрос в 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 ответ(ов)

1

При проведении тестирования производительности для различных подходов к выборке данных, я использовал следующие три метода:

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 продемонстрировал наилучшие результаты по времени выполнения в сравнении с остальными подходами.

0

В данном случае можно использовать аналитическое решение с единственным вложенным запросом. Ваш запрос может выглядеть следующим образом:

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(), которая гарантирует уникальность назначаемых номеров строк.

0

В версии 21c вы можете просто применить ограничение, используя следующий запрос:

SELECT * FROM course WHERE ROWNUM <= 10;

Этот запрос вернет первые 10 записей из таблицы course.

0

Вы начали подготовку к экзамену 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;

Это позволяет удобно управлять выводом данных и сокращать объем результатов выборки. Если у вас есть дополнительные вопросы или требуется помощь с другой частью подготовки, не стесняйтесь задавать!

0

В 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;

Этот подход обеспечит правильное применение сортировки перед применением ограничения по количеству строк.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь