T-SQL: пейджинг с привязками
Я пытаюсь реализовать подкачку, которая немного отличается.
Для простого примера предположим, что у меня есть таблица, определенная и заполненная следующим образом:
DECLARE @Temp TABLE
(
ParentId INT,
[TimeStamp] DATETIME,
Value INT
);
INSERT INTO @Temp VALUES (1, '1/1/2013 00:00', 6);
INSERT INTO @Temp VALUES (1, '1/1/2013 01:00', 7);
INSERT INTO @Temp VALUES (1, '1/1/2013 02:00', 8);
INSERT INTO @Temp VALUES (2, '1/1/2013 00:00', 6);
INSERT INTO @Temp VALUES (2, '1/1/2013 01:00', 7);
INSERT INTO @Temp VALUES (2, '1/1/2013 02:00', 8);
INSERT INTO @Temp VALUES (3, '1/1/2013 00:00', 6);
INSERT INTO @Temp VALUES (3, '1/1/2013 01:00', 7);
INSERT INTO @Temp VALUES (3, '1/1/2013 02:00', 8);
TimeStamp
всегда будет тем же самым интервалом, например. ежедневные данные, данные за 1 час, данные за 1 минуту и т.д. Это не будет смешанным.
Для отчетов и презентаций я хочу реализовать пейджинг, который:
- Заказы
TimeStamp
- Запускается с использованием предлагаемого
pageSize
(скажем, 4), но будет автоматически настраиваться на включение дополнительных записей, соответствующих TimeStamp
. Другими словами, если 1/1/2013 01:00 включен для одного ParentId
, предлагаемый pageSize
будет переопределен, и все записи за час 01:00 будут включены для всех ParentId's
. Это почти как опция TOP WITH TIES
.
Таким образом, запуск этого запроса с помощью pageSize
из 4 будет возвращать 6 записей. Есть 3 часа 00:00 и 1 час 01:00
по умолчанию, но поскольку есть больше часа 01:00's
, pageSize
будет отменено, чтобы вернуть весь час 00:00
и 01:00
.
Вот что у меня до сих пор, и я думаю, что я близок, поскольку он работает для первой итерации, но секвенционные запросы для следующих строк pageSize+
не работают.
WITH CTE AS
(
SELECT ParentId, [TimeStamp], Value,
RANK() OVER(ORDER BY [TimeStamp]) AS rnk,
ROW_NUMBER() OVER(ORDER BY [TimeStamp]) AS rownum
FROM @Temp
)
SELECT *
FROM CTE
WHERE (rownum BETWEEN 1 AND 4) OR (rnk BETWEEN 1 AND 4)
ORDER BY TimeStamp, ParentId
ROW_NUMBER обеспечивает минимальное значение pageSize, но RANK будет содержать дополнительные связи.
Ответы
Ответ 1
Я думаю, что ваша стратегия использования row_number()
и rank()
является чрезмерно сложной.
Просто выберите верхние 4 временных метки из данных. Затем выберите любые отметки времени, которые соответствуют этим:
select *
from @temp
where [timestamp] in (select top 4 [timestamp] from @temp order by [TimeStamp])
Ответ 2
declare @Temp as Table ( ParentId Int, [TimeStamp] DateTime, [Value] Int );
insert into @Temp ( ParentId, [TimeStamp], [Value] ) values
(1, '1/1/2013 00:00', 6),
(1, '1/1/2013 01:00', 7),
(1, '1/1/2013 02:00', 8),
(2, '1/1/2013 00:00', 6),
(2, '1/1/2013 01:00', 7),
(2, '1/1/2013 02:00', 8),
(3, '1/1/2013 00:00', 6),
(3, '1/1/2013 01:00', 7),
(3, '1/1/2013 02:00', 8);
declare @PageSize as Int = 4;
declare @Page as Int = 1;
with Alpha as (
select ParentId, [TimeStamp], Value,
Rank() over ( order by [TimeStamp] ) as Rnk,
Row_Number() over ( order by [TimeStamp] ) as RowNum
from @Temp ),
Beta as (
select Min( Rnk ) as MinRnk, Max( Rnk ) as MaxRnk
from Alpha
where ( @Page - 1 ) * @PageSize < RowNum and RowNum <= @Page * @PageSize )
select A.*
from Alpha as A inner join
Beta as B on B.MinRnk <= A.Rnk and A.Rnk <= B.MaxRnk
order by [TimeStamp], ParentId;
ИЗМЕНИТЬ:
Альтернативный запрос, который присваивает номера страниц по мере их перехода, так что следующая/предыдущая страница может быть реализована без перекрывающихся строк:
with Alpha as (
select ParentId, [TimeStamp], Value,
Rank() over ( order by [TimeStamp] ) as Rnk,
Row_Number() over ( order by [TimeStamp] ) as RowNum
from @Temp ),
Beta as (
select ParentId, [TimeStamp], Value, Rnk, RowNum, 1 as Page, 1 as PageRow
from Alpha
where RowNum = 1
union all
select A.ParentId, A.[TimeStamp], A.Value, A.Rnk, A.RowNum,
case when B.PageRow >= @PageSize and A.TimeStamp <> B.TimeStamp then B.Page + 1 else B.Page end,
case when B.PageRow >= @PageSize and A.TimeStamp <> B.TimeStamp then 1 else B.PageRow + 1 end
from Alpha as A inner join
Beta as B on B.RowNum + 1 = A.RowNum
)
select * from Beta
option ( MaxRecursion 0 )
Обратите внимание, что рекурсивные CTE часто плохо масштабируются.