пятница, 17 мая 2013 г.

Пагинация в Oracle

Как известно, БД от Oracle не поддерживает инструкцию LIMIT в SQL-запросах. Поэтому на первых порах часто возникают вопросы, о том как реализовать пагинацию в Oracle. Тут на самом деле все просто. Достаточно использовать rownum, например вот так:
select *
from some_table
where <some_conditions>
  and rownum >= 1
  and rownum < 20

Казалось бы ВОТ ОНО. Но не тут то было. Как только возникает потребность реализовать пагинацию над некой агрегированной выборкой (выборка с использованием групповых функций), приходится выполнить ряд дополнительных телодвижений:
select tmp.*
from
  (select field1,
          count(field2) field2_cnt
          sum(field3) field3_sum
   from some_table
   where <some_conditions>
   group by field1) tmp
where rownum >= 1
  and rownum < 20
Что здесь происходит? Здесь сначала делается выборка по полям, удовлетворяющим условиям, выполняются групповые операции над ними, затем отсечку по rownum делаем уже над сгруппированными данными, таким образом падгинация работает, как и ожидалось. Вот такой вот небольшой хинт. Ну и всё это можно обернуть в некую хранимую функцию на pl/sql:

funсtion get_padgination_cursor(page in integer := 1) return sys_ref_cursor as
  cr sys_ref_cursor;
  records_per_page integer := 20;
  start_limit integer := records_per_page * (page - 1) + 1;
  stop_limit integer := start_limit + records_per_page;
begin
  open cr for
    select tmp.*
    from
      (select field1,
              count(field2) field2_cnt
              sum(field3) field3_sum
       from some_table
       where <some_conditions>
       group by field1) tmp
    where rownum >= start_limit
      and rownum < stop_limit;

  return cr;
end;