Пейджинг с Oracle и SQL Server и общий метод пейджинга - PullRequest
7 голосов
/ 28 января 2009

Я хочу реализовать разбиение на страницы в виде таблицы или в HTML-таблице, которую я буду заполнять с помощью ajax Как мне написать запросы для поддержки подкачки? Например, если размер страницы равен 20 и когда пользователь щелкает страницу 3, строки от 41 до 60 должны отображаться в таблице. Сначала я могу получить все записи и поместить их в кеш, но я думаю, что это неправильный путь. Потому что данные могут быть очень большими, и данные могут отличаться от других сеансов. так как я могу это реализовать? Есть ли какой-либо общий способ (для всех баз данных)?

Ответы [ 7 ]

17 голосов
/ 06 февраля 2009

Как уже предлагали другие, вы можете использовать rownum в Oracle. Хотя это немного сложно, и вам нужно дважды вложить ваш запрос.

Например, чтобы разбить запрос на страницы

select first_name from some_table order by first_name

тебе нужно вложить это так

select first_name from
  (select rownum as rn, first_name from
    (select first_name from some_table order by first_name)
  ) where rn > 100  and rn <= 200

Причина этого в том, что rownum определяется после предложения where и до order by предложения. Чтобы понять, что я имею в виду, вы можете запросить

select rownum,first_name from some_table order by first_name

и вы можете получить

4   Diane
2   Norm
3   Sam
1   Woody

Это потому, что oracle оценивает предложение where (в данном случае ни одного), затем присваивает rownums, а затем сортирует результаты по first_name. Вы должны вложить запрос так, чтобы он использовал rownum, назначенный после строки были отсортированы.

Второе вложение связано с тем, как обрабатывается rownum в состоянии where. По сути, если вы запросите «где rownum> 100», то вы не получите результатов. Это просто курица и яйцо, где он не может вернуть ни одной строки, пока не найдет rownum> 100, но, поскольку он не возвращает никаких строк, он никогда не увеличивает rownum, поэтому он никогда не считается до 100. Тьфу. Второй уровень вложенности решает это. Обратите внимание, что в этот момент он должен иметь псевдоним столбца rownum.

Наконец, ваш заказ по предложению должен сделать запрос детерминированным. Например, если у вас есть Джон Доу и Джон Смит, и вы заказываете только по имени, то они могут переключаться между выполнением одного запроса на другое.

Здесь есть статьи http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html и вот http://www.oracle.com/technology/oramag/oracle/07-jan/o17asktom.html. Теперь, когда я вижу, как долго мое сообщение, я, вероятно, должен был просто опубликовать эти ссылки ...

4 голосов
/ 28 января 2009

К сожалению, методы ограничения диапазона строк, возвращаемых запросом, варьируются от одной СУБД к другой: Oracle использует ROWNUM (см. Ответ ocdecio), но ROWNUM не будет работать в SQL Server.

Возможно, вы можете инкапсулировать эти различия с помощью функции, которая принимает заданный оператор SQL и номера первой и последней строк и генерирует соответствующий SQL-код paginatd для целевой СУБД, т.е. что-то вроде:

sql = paginated ('select empno, ename from emp where job = ?', 101, 150)

, который вернул бы

'select * from (select v.*, ROWNUM rn from ('
 + theSql
 + ') v where rownum < 150) where rn >= 101'

для Oracle и что-то еще для SQL Server.

Однако обратите внимание, что решение Oracle добавляет новый столбец RN к результатам, с которыми вам придется иметь дело.

1 голос
/ 23 ноября 2010
select * 
  from ( select /*+ FIRST_ROWS(n) */   a.*,
      ROWNUM rnum 
      from ( your_query_goes_here, 
      with order by ) a 
      where ROWNUM <= 
      :MAX_ROW_TO_FETCH ) 
where rnum  >= :MIN_ROW_TO_FETCH;

Шаг 1: ваш запрос с заказом по

Шаг 2: select a.*, ROWNUM rnum from ()a where ROWNUM <=:MAX_ROW_TO_FETCH

Шаг 3: select * from ( ) where rnum >= :MIN_ROW_TO_FETCH; положить 1 в 2 и 2 в 3

1 голос
/ 29 января 2009

"Потому что ... данные могут отличаться от других сессий." Что вы хотите, чтобы это случилось?

Например, пользователь получает «последние» десять строк в 10:30.

В 10:31 добавлены 3 новые строки (поэтому те десять, которые пользователь просматривает, больше не являются последними). ​​

В 10:32 пользователь запрашивает «следующие» десять записей.

Хотите ли вы, чтобы этот новый набор включал те три, которые были повышены с 8/9/10 до 11/12/13? Если нет, в Oracle вы можете выбрать данные, как это было в 10:30

SELECT * FROM table_1 as of timestamp (timestamp '2009-01-29 10:30:00'); 

Вам все еще нужна логика row_number, например,

 select * from
    (SELECT a.*, row_number() over (order by hire_date) rn
    FROM hr.employees as of timestamp (timestamp '2009-01-29 10:30:00') a)
 where rn between 10 and 19
1 голос
/ 28 января 2009

Я считаю, что оба имеют аналитическую функцию ROWNUM. Используйте это, и вы будете идентичны.

В Oracle это здесь

ROW_NUMBER

Да, только что проверил, что ROW_NUMBER является одинаковой функцией в обоих.

0 голосов
/ 01 февраля 2009

Не существует единого способа обеспечения разбиения на страницы для различных продуктов RDBMS. Oracle дает вам rownum, который вы можете использовать в выражении where, например:

where rownum < 1000

SQL Server предоставляет вам функцию row_id (), которую можно использовать аналогично функции rownum в Oracle. Однако row_id () недоступен до SQL Server 2005.

0 голосов
/ 29 января 2009

Если ожидаемый набор данных огромен, я бы рекомендовал создать временную таблицу, представление или снимок (материализованное представление) для хранения результатов запроса + номер строки, полученный с использованием аналитической функции ROWNUM или ROW_NUMBER. После этого вы можете просто запросить это временное хранилище, используя диапазоны номеров строк. По сути, вам необходимо отделить фактическую выборку данных от подкачки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...