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 минуту и т. д. Он не будет смешиваться.

для целей отчетности и презентации я хочу реализовать пейджинг, который:

  1. заказы TimeStamp
  2. начинается с использования предложенного pageSize (скажем, 4), но автоматически настраивается для включения дополнительных записей, соответствующих на TimeStamp. Другими словами, если 1/1/2013 01:00 для одного ParentId, предложил pageSize будет переопределен, и все записи за час 01: 00 будут включены для всех ParentId's. Это почти как .

Итак, запуск этого запроса с pageSize из 4 вернет 6 записей. Есть 3 часа 00:00 и 1 час 01:00 по умолчанию, но потому, что есть больше часа 01:00's, the 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 обеспечивает минимальный размер страницы, но ранг будет включать дополнительные связи.

2 ответов


Я думаю, что ваша стратегия использования row_number() и rank() это усложнять вещи.

просто выберите верхние 4 метки времени из данных. Затем выберите любые метки времени, соответствующие этим:

select *
from @temp
where [timestamp] in (select top 4 [timestamp] from @temp order by [TimeStamp])

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 )

обратите внимание, что рекурсивные CTEs часто масштабируются плохо.