10

我正在尝试实现一个有点不同的分页例程。

为了一个简单的例子,假设我有一个定义和填充的表,如下所示:

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 包含在 oneParentId中,则建议pageSize将被覆盖,并且所有 01:00 小时的记录都将包含在 allParentId's中。这几乎就像TOP WITH TIES选项一样。

因此,使用 of 4 运行此查询pageSize将返回 6 条记录。默认情况下有 3 小时 00:00 和 1 小时01:00,但是因为有更多 hour 01:00's,所以pageSize将被覆盖以返回所有 hour00:0001: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 将包括额外的关系。

4

2 回答 2

1
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 的扩展性通常很差。

于 2013-05-31T16:44:24.427 回答
0

我认为你使用的策略row_number()rank()过于复杂的事情。

只需从数据中选择前 4 个时间戳。然后选择与这些匹配的任何时间戳:

select *
from @temp
where [timestamp] in (select top 4 [timestamp] from @temp order by [TimeStamp])
于 2013-06-01T07:25:49.237 回答