T-SQL:使用TIES进行分页

时间:2013-05-31 15:29:13

标签: sql sql-server-2008 tsql

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

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

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匹配的其他记录。换句话说,如果一个ParentId包含1/1/2013 01:00,则会覆盖建议的pageSize,并且所有{{1}将包含小时01:00的所有记录}。它几乎就像ParentId's选项。
  3. 因此,以TOP WITH TIES为4运行此查询将返回6条记录。默认情况下,有3小时00:00和1小时pageSize,但因为还有更多小时01:00,所以会覆盖01:00's以返回所有小时pageSize和{ {1}}。

    这是我到目前为止的内容,我认为我很接近,因为它适用于第一次迭代,但后续00:00行的后续查询不起作用。

    01:00

    ROW_NUMBER确保满足最小pageSize,但RANK将包含额外的关系。

2 个答案:

答案 0 :(得分: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通常表现不佳。

答案 1 :(得分:0)

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

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

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