2016-03-02 99 views
2

SQL Server 2008r2TSQL計算事件塊之間的時間間隔

您能幫我計算事件塊之間的持續時間嗎?

實施例的數據集

Id NodeId StartTime   NextId 
16 87771 2016-02-01 11:01:00 17 
17 87771 2016-02-01 11:02:00 18 
18 87771 2016-02-01 11:03:00 19 
19 87771 2016-02-01 11:05:00 NULL 

27 87774 2016-02-01 08:43:00 28 
28 87774 2016-02-01 08:44:00 29 
29 87774 2016-02-01 08:46:00 30 
30 87774 2016-02-01 08:47:00 NULL 

40 87771 2016-02-01 11:52:00 41 
41 87771 2016-02-01 11:53:00 42 
42 87771 2016-02-01 11:55:00 NULL 

72 87774 2016-02-01 10:07:00 73 
73 87774 2016-02-01 10:08:00 74 
74 87774 2016-02-01 10:09:00 75 
75 87774 2016-02-01 10:11:00 76 
76 87774 2016-02-01 10:13:00 NULL 

的ID 16之間以秒的時間差後,我 - 19和27 - 30和40 - 42等

所以預期結果

NodeId Duration_Seconds 
87771 240 
87774 240 
87771 180 
87774 360 

提前致謝。

+0

您是否嘗試過使用DATEDIFF()函數? https://msdn.microsoft.com/en-us/library/ms189794.aspx –

回答

2

假設事件的塊不與其它的塊交錯,然後將溶液是識別每個塊通過使用「窗口函數」在NextId列中(從下到上)運行NULLS。

然後,您可以輕鬆找到每個塊中的最小和最大StartTime值。

with blocks as (
    select *, 
     sum(case when NextId is null then 1 else 0 end) over (order by Id desc) as BlockId 
    from #TEMP 
) 
select NodeId, DATEDIFF(second,min(StartTime), max(StartTime)) as Duration_Seconds 
from blocks 
group by BlockId, NodeId 
order by BlockId desc 

我用它填充從answer by Kamran

+0

與迄今爲止給出的答案相比,這是最有效和最整潔的,並且需要最少的代碼行。好的。 – Jayvee

+0

喜歡它約翰里斯 –

0

這裏使用CURSOR yuk !!!

示例數據:

IF OBJECT_ID('tempdb..#TEMP') IS NOT NULL 
    DROP TABLE #TEMP; 

CREATE TABLE #TEMP(Id  INT, 
       NodeId INT, 
       StartTime DATETIME, 
       NextId INT); 

INSERT INTO #TEMP 
VALUES 
     (16, 87771, '2016-02-01 11:01:00', 17), 
     (17, 87771, '2016-02-01 11:02:00', 18), 
     (18, 87771, '2016-02-01 11:03:00', 19), 
     (19, 87771, '2016-02-01 11:05:00', NULL), 
     (27, 87774, '2016-02-01 08:43:00', 28), 
     (28, 87774, '2016-02-01 08:44:00', 29), 
     (29, 87774, '2016-02-01 08:46:00', 30), 
     (30, 87774, '2016-02-01 08:47:00', NULL), 
     (40, 87771, '2016-02-01 11:52:00', 41), 
     (41, 87771, '2016-02-01 11:53:00', 42), 
     (42, 87771, '2016-02-01 11:55:00', NULL), 
     (72, 87774, '2016-02-01 10:07:00', 73), 
     (73, 87774, '2016-02-01 10:08:00', 74), 
     (74, 87774, '2016-02-01 10:09:00', 75), 
     (75, 87774, '2016-02-01 10:11:00', 76), 
     (76, 87774, '2016-02-01 10:13:00', NULL); 

QUERY:

-- pull the data into a staging table with an extra column to hold GroupID 


IF OBJECT_ID('tempdb..#TEMP2') IS NOT NULL 
    DROP TABLE #TEMP2; 

SELECT *, 
     CAST(NULL AS INT) AS groupID 
INTO #temp2 
FROM #TEMP; 

-- Unfortunately I cant see any other way except using a cursor put the results into groups. I really hate using cursors but... 


DECLARE @NodeId INT, 
     @id  INT, 
     @nextid INT, 
     @groupID INT = 1; 

DECLARE group_Cursor CURSOR 
FOR SELECT NodeId, 
     Id, 
     NextId 
    FROM #TEMP 
    ORDER BY Id; 

OPEN group_Cursor; 

FETCH NEXT FROM group_Cursor INTO @NodeId, 
          @id, 
          @nextid; 

WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SELECT @NodeId, 
      @id, 
      @nextid; 
     UPDATE A 
     SET A.groupID = @groupID 
     FROM #temp2 AS A 
     WHERE A.NodeId = @NodeId 
      AND A.Id = @id; 
     FETCH NEXT FROM group_Cursor INTO @NodeId, 
            @id, 
            @nextid; 
     IF @nextid IS NULL 
      SELECT @groupID+=1; 
    END; 

CLOSE group_Cursor; 

DEALLOCATE group_Cursor; 

-- this is to resolve a bug where it gives groupID an extra increment if nextid IS NULL not sure why that's happening  
UPDATE t 
    SET t.groupID = t.groupID - 1 
FROM #temp2 t 
WHERE nextid IS NULL; 

SELECT t1.NodeId, 
     SUM(DATEDIFF(SECOND, t1.StartTime, t2.StartTime)) 
FROM #TEMP2 AS t1 
     INNER JOIN #TEMP2 AS t2 ON t1.NodeId = t2.NodeId 
          AND t1.NextId = t2.Id 
GROUP BY t1.NodeId, 
     t1.groupID; 

結果:

enter image description here

+0

謝謝,但不想實現遊標 –

+0

@Mountaineer我不怪你。它們總是最後的手段 –

0

做的另一種方式是通過遞歸:

--using the sample data in #temp as kindly provided by Kamran 
    ;with cte as 
    (select id,nodeid, starttime, 0 as timediff, nextid from #temp where nextid is null 
    union all 
    select t.id, t.nodeid, t.starttime, datediff(second,t.starttime,c.starttime)+c.timediff timediff, t.nextid 
    from cte c 
    join #temp t on t.nextid=c.id 
    ) 
    select nodeid, timediff from cte c1 
    where not exists (select 1 from cte c2 where c2.nextid=c1.id) 
    order by id 

(我假設有塊內沒有id間隙但有塊之間ID間隙)

0

我結束了這樣的複製#TEMP表的設置。

--using the sample data in #temp as kindly provided by Kamran 
    SELECT 
     C.NodeId 
     ,SUM(DATEDIFF(SS, N.StartTime, C.StartTime)) 
    FROM 
     #TEMP C 
    CROSS APPLY 
    (
     SELECT TOP 1 
      NodeId 
      ,StartTime 
     FROM 
      #TEMP M 
     WHERE 
      ID = C.ID - 1 
    ) N 
    WHERE 
     N.NodeId = C.NodeId 
    GROUP BY 
      C.NodeId