2017-01-18 89 views
5

我有一些包含日期的數據。我試圖按連續日期對數據進行分組,但是,日期並不完全相同。下面是一個例子:分批產生當日期不完全連續時,按連續日期記錄組記錄

DateColumn    | Value 
------------------------+------- 
2017-01-18 01:12:34.107 | 215426 <- batch no. 1 
2017-01-18 01:12:34.113 | 215636 
2017-01-18 01:12:34.623 | 123516 
2017-01-18 01:12:34.633 | 289926 
2017-01-18 04:58:42.660 | 259063 <- batch no. 2 
2017-01-18 04:58:42.663 | 261830 
2017-01-18 04:58:42.893 | 219835 
2017-01-18 04:58:42.907 | 250165 
2017-01-18 05:18:14.660 | 134253 <- batch no. 3 
2017-01-18 05:18:14.663 | 134257 
2017-01-18 05:18:14.667 | 134372 
2017-01-18 05:18:15.040 | 181679 
2017-01-18 05:18:15.043 | 226368 
2017-01-18 05:18:15.043 | 227070 

數據和批量內的各行需要幾毫秒來生成。我想組結果如下:

Date1     | Date2     | Count 
------------------------+-------------------------+------ 
2017-01-18 01:12:34.107 | 2017-01-18 01:12:34.633 | 4 
2017-01-18 04:58:42.660 | 2017-01-18 04:58:42.907 | 4 
2017-01-18 05:18:14.660 | 2017-01-18 05:18:15.043 | 6 

它是安全的假設,如果連續兩次排在1分鐘以上,然後分開它們屬於不同的批次。

我嘗試了涉及ROW_NUMBER函數的解決方案,但它們使用連續日期(兩行之間的日期差異是固定的)。當差異模糊時,我怎樣才能達到理想的效果?


請注意,一批可能比一分鐘長得多。例如,批次可能包含從2017-01-01 00:00:00開始到2017-01-01 00:05:00結束的行,由〜3000行組成,每行相隔數十或數百毫秒。可以肯定的是批次間隔至少1分鐘。

+0

重新「安全......」我們不能說 - 業務或其他領域的專家會唯一可以說的人。如果批量處理,您需要每個批次的標識符,並使用 – Mark

+0

所討論的最後兩行是否具有相同的日期時間值,或者是否是拼寫錯誤? –

+0

@vkp這很奇怪,但不是錯字。也許在1毫秒內插入兩行或實際時間四捨五入到最接近的'datetime'值。 –

回答

8

試試這個:

select min(t.dateColumn) date1, max(t.dateColumn) date2, count(*) 
from (
    select t.*, sum(val) over (
      order by t.dateColumn 
      ) grp 
    from (
     select t.*, case 
       when datediff(ms, lag(t.dateColumn, 1, t.dateColumn) over (
          order by t.dateColumn 
          ), t.dateColumn) > 60000 
        then 1 
       else 0 
       end val 
     from your_table t 
     ) t 
    ) t 
group by grp; 

產地:

enter image description here

使用分析功能lag()基礎上datecolumn與上一次的不同標記下一批開始,然後使用分析sum()上創建一組批次,然後按它來分組以找到所需的聚合。

由於與DATETIME的舍入問題,組中可能存在某些分類錯誤。從MSDN,

將日期時間值四捨五入爲增量.000,.003或.007秒,如下表所示。

enter image description here


下面是使用CTE重寫相同的查詢:

WITH cte1(DateColumn, ValueColumn) AS (
    -- Insert your query that returns a datetime column and any other column 
    SELECT 
     SomeDate, 
     SomeValue 
    FROM SomeTable 
    WHERE SomeColumn IS NOT NULL 
), cte2 AS (
    -- This query adds a column called "val" that contains 
    -- 1 when current row date - previous row date > 1 minute 
    -- 0 otherwise 
    SELECT 
     cte1.*, 
     CASE WHEN DATEDIFF(MS, LAG(DateColumn, 1, DateColumn) OVER (ORDER BY DateColumn), DateColumn) > 60000 THEN 1 ELSE 0 END AS val 
    FROM cte1 
), cte3 AS (
    -- This query adds a column called "grp" that numbers 
    -- the groups using running sum over the "val" column 
    SELECT 
     cte2.*, 
     SUM(val) OVER (ORDER BY DateColumn) AS grp 
    FROM cte2 
) 
SELECT 
    MIN(DateColumn) Date1, 
    MAX(DateColumn) Date2, 
    COUNT(ValueColumn) [Count] 
FROM cte3 
GROUP BY grp 
+1

創建羣組的好方法 – Aquillo

+0

不應該是'datediff(second ...)> 60'嗎? – Serg

+0

考慮'選擇datediff(mi,'2017-01-18 01:12:20','2017-01-18 01:13:31'),datediff(秒,'2017-01-18 01:12:20 ','2017-01-18 01:13:31')',我的理解是那些應該是不同的羣體 – Serg

0

這不工作,如果youre比較日期(60歲)之間的差距。但你可以試試這個,如果你需要得到記錄,那屬於同一分鐘X.

SELECT 
    [Date1] = MIN([DateColumn]) 
    ,[Date2] = MAX([DateColumn]) 
    ,[Count] = COUNT([DateColumn]) 
FROM 
    [my_table] 
GROUP BY 
    DATEADD(mi, DATEDIFF(mi, 0, [DateColumn]), 0);