|
|
От: |
bmv
|
|
| Дата: | 25.06.03 05:05 | ||
| Оценка: | |||
Спасибо за развернутый ответ, все это, конечно, здорово, только все-таки как решить при этом вопрос с прокруткой данных пользователемLG>Вопрос порционной(постраничной) выборки тесно связан с вопросом нумерации строк в запросе (см. FAQ.Нумерация записей в запросе). Другими словами, для того, чтобы выбрать N-ую порцию из результатов запроса, нужно сначала пронумеровать результаты этого запроса.
LG>Отсюда и похожие методы решения
LG>Вариант 1 «Классический».
LG>SELECT TOP 100 * FROM MyTable
LG>WHERE id NOT IN (SELECT TOP 100 id FROM MyTable ORDER BY id) ORDER BY id
LG>Главный недостаток этого метода в в том, что т.к. TOP n записей выбираются уже из конечного результата запроса, то проверка условия WHERE будет выполняться для каждой строки главного запроса. При этом, время выполнения этой проверки будет расти вместе с номером выбираемой порции(страницы). Если, например, таблица содержит 100 записей и необходимо выбирать данные порциями по 10 записей, то
LG>для 2-ой порции нужно будет будет проверять подзапрос из 10 записей
LG>для 3-ей порции нужно будет будет проверять подзапрос из 20 записей
LG>для 4-ой порции нужно будет будет проверять подзапрос из 30 записей и т.д.
LG>Достоинство метода в его универсальности, академичности. Он не требует специфики T-SQL, этот метод можно применить практически на любом SQL-сервере.
LG>Вариант 2 «Эффективный, специфический для T-SQL».
LG>Как и в случае нумерации строк данный метод основан на использовании временной таблицы. Для удобства оформим наш запрос как хранимую процедуру, возвращающую n-ую порцию(страницу), содержащую m записей
LG>CREATE PROCEDURE dbo.get_this_page (@rec_per_page int, @page_num int) AS
LG>SELECT identity(int, 1,1) AS RowNum, MyId AS OrigId INTO #tmp FROM mytable
LG>SELECT b.* FROM #tmp AS a
LG>INNER JOIN mytable AS b on a.OrigId = b.MyId
LG>WHERE a.RowNum BETWEEN (@rec_per_page * @page_num + 1)
LG>AND (@rec_per_page * (@page_num + 1))
LG>DROP TABLE #tmp
LG>Прмечания.
LG>- предложенный вариант процедуры будет блокировать базу tempdb на все время выполнения 1-го запроса. Если время блокировки становиться неприемлимым, то необходимо разбить этот запрос таким образом
LG>CREATE TABLE #temp(RowNum int identity, OrigId int)
LG>INSERT INTO #temp(OrigId) SELECT MyId FROM mytable
LG>- Если, поле MyId было создано признаком «IDENTITY», то это поле в запросе необходимо «завернуть» в функцию «CONVERT», иначе будет сообщение об ошибке.
LG>Glory