#pagination #sybase
#разбивка на страницы #sybase
Вопрос:
Есть ли какой-нибудь простой способ реализовать разбивку на страницы в sybase? В postgres есть ограничение и смещение, в mysql есть ограничение X, Y. Что насчет sybase? Существует ограничение top для ограничения результатов, но для достижения полной разбивки на страницы также требуется смещение. Это не проблема, если есть несколько страниц, я могу просто обрезать результаты на стороне клиента, но если есть миллионы строк, я хотел бы получать только те данные, которые мне нужны.
Комментарии:
1. Речь идет о Sybase ASE или Sybase SQL где-нибудь? SQL Anywhere поддерживает
TOP .. START WITH ..
Ответ №1:
// First row = 1000
// Last row = 1009
// Total row = 1009 - 1000 1 = 10
// Restriction: exec sp_dboption 'DATABASE_NAME','select into/bulkcopy','true'
select TOP 1009 *, rownum=identity(10)
into #people
from people
where upper(surname) like 'B%'
select * from #people where rownum >= 1000
drop table #people
// It shoulde be better SQL-ANSI-2008 (but we have to wait):
// SELECT * FROM people
// where upper(surname) like 'B%'
// OFFSET 1000 ROWS FETCH NEXT 10 ROWS ONLY
Ответ №2:
Я очень опаздываю на вечеринку, но я случайно наткнулся на эту проблему и нашел лучший ответ, используя TOP и START AT из документа sybase. Вам нужно использовать ORDER BY для, иначе вы получите непредсказуемые результаты.
http://dcx.sybase.com/1101/en/dbusage_en11/first-order-formatting.html
ВЫБЕРИТЕ TOP 2, НАЧИНАЯ С 5 *, ИЗ ПОРЯДКА сотрудников ПО фамилии DESC;
Комментарии:
1. OP не сказал, какую версию Sybase они использовали, но стоит отметить, что этот ответ работает в SQL где угодно, но не в Sybase ASE.
Ответ №3:
Цитирование из http://www.isug.com/Sybase_FAQ/ASE/section6.2.html#6.2.12:
Sybase не имеет прямого эквивалента Oracle rownum, но его функциональность может быть эмулирована во многих случаях.
Вы можете установить максимальное rowcount
значение, которое ограничит количество строк, возвращаемых любым конкретным запросом:
set rowcount 150
Это ограничение будет применяться до тех пор, пока оно не будет сброшено:
set rowcount 0
Вы можете выбрать временную таблицу, а затем извлечь из нее данные:
set rowcount 150
select pseudo_key = identity(3),
col1,
col2
into #tempA
from masterTable
where clause...
order by 2,3
select col1,col2 from #tempA where pseudo_key between 100 and 150
Вы можете оптимизировать хранилище во временной таблице, сохранив только столбцы идентификаторов, которые затем присоединяются к исходной таблице для выбора.
В FAQ также предлагаются другие решения, включая курсоры или Sybperl.
Ответ №4:
Пример Sybase SQL Anywhere, строк на странице: 10, смещение: 1000.
SELECT top 10 start at 1001 * FROM employee order by employeeid
Примечание: необходимо указать order by
столбец.
Ответ №5:
начиная с версии 16.x, Sybase ASE поддерживает ссылку на ОГРАНИЧЕНИЕ и СМЕЩЕНИЕ: https://help.sap.com/docs/SAP_ASE/e0d4539d39c34f52ae9ef822c2060077/26d84b4ddae94fed89d4e7c88bc8d1e6.html?version=16.0.2.5amp;locale=en-US#using-limit-and-offset-together
Комментарии:
1. TBH это единственное упоминание в Интернете об этом, и я играю на живом сервере, и, похоже, это не работает… Также это говорит о чем-то другом: infocenter.sybase.com/help/index.jsp?topic =/…
2. Похоже, вы ссылаетесь на устаревшую документацию. Вы должны убедиться, что у вас есть версия ASE, которая поддерживает это.
Ответ №6:
К сожалению, Sybase не предоставляет возможности устанавливать ограничение начала и смещения. Лучшее, чего вы можете достичь, это использовать SET ROWCOUNT для ограничения количества возвращаемых записей. Если у вас есть 1000 записей и вы хотите разбить страницу на 50 записей, то что-то вроде этого вернет первую страницу…
set rowcount 50
select * from orders
Для второй страницы…
set rowcount 100
select * from orders
… и затем вы можете выбрать не отображать первые 50 из вашего Java-кода. Очевидно, что при переадресации страниц вам в конечном итоге приходится возвращать все большие и большие наборы данных. Ваш вопрос о том, что делать с 1 000 000 записей, не кажется практичным для пользовательского интерфейса, который разбит на страницы. Пользователь не выполняет поиск в Google, а затем перелистывает страницы 1000 раз в поисках материала.
Что, если у меня есть естественный ключ?
Если у вас есть относительно большой набор данных, и вы можете использовать естественный ключ для своих данных, это поможет ограничить возвращаемые записи. Например, если у вас есть список контактов и есть интерфейс, который позволяет вашим пользователям выбирать от А до Я, чтобы отображать людей в каталоге на основе фамилии, тогда вы можете сделать что-то вроде…
set rowcount 50
select * from people
where upper(surname) like 'B%'
Когда есть более 50 человек с фамилией, начинающейся с «B», вы используете тот же подход, что и выше, для переадресации страницы…
set rowcount 100
select * from people
where upper(surname) like 'B%'
… и удалите первые 50 в коде Java.
Следуя этому примеру, возможно, вы можете ограничить поиск по дате или какой-либо другой части данных, значимой для ваших запросов пользователей.
Надеюсь, это поможет!
Ответ №7:
Вы могли бы попробовать использовать set ROWCOUNT дважды, как это:
объявляем @skipRows int, @GetRows int ВЫБИРАЕМ @skipRows=50 ВЫБЕРИТЕ @GetRows=10 установите КОЛИЧЕСТВО СТРОК @skipRows ВЫБЕРИТЕ caslsource_id в #caslsource_paging ИЗ caslsources set rowcount @GetRows Выберите * из caslsources, где caslsource_id отсутствует (выберите caslsource_id из #caslsource_paging) УДАЛЕНИЕ ТАБЛИЦЫ #caslsource_paging
Это создает временную таблицу строк для пропуска. Вам нужно будет добавить предложения WHERE и ORER BY к обоим выбранным, чтобы пропустить нужные страницы.
Ответ №8:
Я не знаю, является ли это ASE или другим продуктом, но следующий шаблон работает в нескольких базах данных, с которыми я работал, если есть способ каким-то образом создать временную таблицу с номером строки, и вы можете определить уникальный ключ для каждой строки:
Входные параметры:
declare @p_first int /* max number of rows to see; may be null (= all results); otherwise must be positive number */
declare @p_skipFirst int /* number of rows to skip before the results; must be nonnegative number */
declare @p_after PKTYPE /* key for the row before you start skipping; may be null */
задана таблица:
RowNumber | RowIndex | DataCol1
1 | 1234 | Joe
2 | 1235 | Sue
3 | 2000 | John
4 | 2005 | Frank
5 | 3000 | Tom
6 | 4000 | Alice
набор параметров:
set @p_first = 5
set @p_skipFirst = 2
set @p_after = 1235
будет представлять строки 5 и 6.
Дополнительный набор параметров может представлять подкачку с конца таблицы в обратном порядке:
declare @p_last int /* max number of rows to see; may be null (= all results); otherwise must be positive number */
declare @p_skipLast int /* number of rows to skip after the results; must be nonnegative number */
declare @p_before PKTYPE /* key for the row after you start skipping; may be null */
Предполагая, что ваша несортированная таблица находится в #resultsBeforeSort
столбце индекса с именем RowIndex
, вы можете отсортировать это с помощью следующего сценария:
select RowNumber = identity(10), *
into #results
from #resultsBeforeSort
/*
you might also wish to have a where clause on this query
this sort is dynamically generated based on a sort expression and
ultimately ended with RowIndex to ensure a deterministic order
*/
order by Column1, Column2 desc, RowIndex
declare @p_total int, @p_min int, @p_max int
select @p_total = count(*) from #results
select @p_min = case when @p_after is null then 1 @p_skipFirst else @p_total 1 end
select @p_min = RowNumber @p_skipFirst from #results where [RowIndex] = @p_after
select @p_max = case when @p_before is null then @p_total - @p_skipLast else 0 end
select @p_max = RowNumber - @p_skipLast from #results where [RowIndex] = @p_before
declare @p_min2 int, @p_max2 int
set @p_min2 = @p_min
set @p_max2 = @p_max
select @p_max2 = case when @p_first is null then @p_max else @p_min @p_first - 1 end
select @p_min2 = case when @p_last is null then @p_min else @p_max - @p_last end
select @p_min = case when @p_min2 > @p_min then @p_min2 else @p_min end
select @p_max = case when @p_max2 < @p_max then @p_max2 else @p_max end
этот скрипт устанавливает параметры @p_min
, @p_max
, и @p_total
, а также временную таблицу #results
Затем вы можете использовать это для выбора фактических данных; выберите 2 результата таблицы, первый из которых — метаданные (выберите это первым, потому что во второй таблице может не быть фактических строк, и ваша реализация reader может быть неспособна справиться с этим без возврата):
select [Count] = @p_total,
HasPreviousPage = (case when @p_min > 1 then 1 else 0 end),
HasNextPage = (case when @p_max 1 < @p_total then 1 else 0 end)
за которым следует постраничное окно результатов, которые вы действительно хотите:
select [RowIndex], Col1, Col2, Col3
from #results where RowNumber between @p_min and @p_max
Выполнение этого общего решения позволяет использовать любую стратегию подкачки, которую вы пожелаете. Вы можете создать потоковое решение (facebook, google, stackoverflow, reddit, …) с помощью @p_after
and @p_first
(или @p_before
and @p_last
). Вы можете сделать смещение взять с @p_first
помощью и @p_skipFirst
. Вы также можете сделать страницу размер с теми же параметрами @p_first = size
и @p_skipFirst = (page - 1) * size
. Далее вы можете использовать более эзотерические стратегии подкачки (последние X страниц, между абсолютными записями, смещение привязка и т. Д.) С другими комбинациями параметров.
При этом Sybase (SAP) ASE теперь напрямую поддерживает стратегию смещения взятия через rows limit @p_first offset @p_skipFirst
. Если бы вы только хотели поддержать эту стратегию, вы могли бы упростить вышесказанное до:
declare @p_total int
select @p_total = count(*) from #resultsBeforeSort
select [Count] = @p_total,
[HasPreviousPage] = (case when @p_skipFirst > 0 then 1 else 0 end),
[HasNextPage] = (case when @p_total > @p_skipFirst @p_first then 1 else 0 end)
select [RowIndex], Col1, Col2, Col3
from #resultsBeforeSort
order by Column1, Column2 desc, RowIndex
rows limit @p_first offset @p_skipFirst