2013-05-31 22 views
10

我正在嘗試實現一個有點不同的分頁例程。T-SQL:與TIES進行分頁

對於一個簡單的例子起見,讓我們假設我有一個表中定義和填充如下:

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將被覆蓋,所有ParentId's的時間01:00的記錄將包含在內。這幾乎就像TOP WITH TIES選項。

因此,使用4的pageSize運行此查詢將返回6條記錄。有3小時00:00和1小時01:00默認情況下,但因爲有更多小時01:00'spageSize將被覆蓋返回所有小時00: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將包含其他關係。

+0

什麼版本的SQL Server? – gbn

+1

對不起。我應該提到我正在使用2008. –

+1

你應該使用時間戳條件。對於第一個查詢'timestamp> minValue'(取決於你的列類型datetime或datetime2)。從查詢結果中讀取時間戳的最大值。對於下面的查詢,你可以使用這個max來過濾:'選擇帶*的頂部4 *來自@temp,其中timestamp> max' – tschmit007

回答

0

我認爲你使用row_number()rank()的策略是過於複雜的事情。

只需從數據中選擇前4個時間戳即可。然後選擇與這些匹配的時間戳:

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

這就是我最終做的。使用row_number和rank使得它更加困難。感謝您的意見。 –

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往往規模不佳。

+0

感謝您的回覆,但PageSize = 1和2,均返回小時01:00的數據。 –

+0

@JohnRussell - 它在SS 2008 R2中爲我工作。頁面大小爲1時,頁面1,2和3將返回相同的午夜數據集。第4,5和6頁返回一組數據。您可以將最終的'select'更改爲'select * from Alpha'或'select * from Beta'來查看發生了什麼。 – HABO

+0

我認爲這個解決方案的問題是頁面重疊。無論先前的頁面是否大於指定的頁面大小,頁面n在(n-1)* pagesize之後的記錄上開始。 – Chad