- Get list with start and end values from table of datetimes
- DeviceID Timestamp Value
- ----------------------------------------
- Device1 1.1.2011 10:00:00 3
- Device1 1.1.2011 10:00:01 4
- Device1 1.1.2011 10:00:02 4
- Device1 1.1.2011 10:00:04 3
- Device1 1.1.2011 10:00:05 4
- Device1 1.1.2011 14:23:14 8
- Device1 1.1.2011 14:23:15 7
- Device1 1.1.2011 14:23:17 4
- Device1 1.1.2011 14:23:18 2
- DeviceID Started Ended
- Device1 1.1.2011 10:00:00 1.1.2011 10:00:05
- Device1 1.1.2011 14:23:14 1.1.2011 14:23:18
- -- Table var to store the gaps
- declare @T table
- (
- DeviceID varchar(10),
- PrevPeriodEnd datetime,
- NextPeriodStart datetime
- )
- -- Get the gaps
- ;with cte as
- (
- select *,
- row_number() over(partition by DeviceID order by Timestamp) as rn
- from data
- )
- insert into @T
- select
- C1.DeviceID,
- C1.Timestamp as PrevPeriodEnd,
- C2.Timestamp as NextPeriodStart
- from cte as C1
- inner join cte as C2
- on C1.rn = C2.rn-1 and
- C1.DeviceID = C2.DeviceID and
- datediff(s, C1.Timestamp, C2.Timestamp) > 5
- -- Build islands from gaps in @T
- ;with cte1 as
- (
- -- Add first and last timestamp to gaps
- select DeviceID, PrevPeriodEnd, NextPeriodStart
- from @T
- union all
- select DeviceID, max(TimeStamp) as PrevPeriodEnd, null as NextPeriodStart
- from data
- group by DeviceID
- union all
- select DeviceID, null as PrevPeriodEnd, min(TimeStamp) as PrevPeriodEnd
- from data
- group by DeviceID
- ),
- cte2 as
- (
- select *,
- row_number() over(partition by DeviceID order by PrevPeriodEnd) as rn
- from cte1
- )
- select
- C1.DeviceID,
- C1.NextPeriodStart as PeriodStart,
- C2.PrevPeriodEnd as PeriodEnd
- from cte2 as C1
- inner join cte2 as C2
- on C1.DeviceID = C2.DeviceID and
- C1.rn = C2.rn-1
- order by C1.DeviceID, C1.NextPeriodStart
- create table Measures (
- DeviceID int not null,
- Occurred datetime not null,
- Value int not null,
- constraint PK_Measures PRIMARY KEY (DeviceID,Occurred)
- )
- go
- insert into Measures (DeviceID,Occurred,Value)
- select 1,'2011-01-01T10:00:00',3 union all
- select 1,'2011-01-01T10:00:01',4 union all
- select 1,'2011-01-01T10:00:02',4 union all
- select 1,'2011-01-01T10:00:04',3 union all
- select 1,'2011-01-01T10:00:05',4 union all
- select 1,'2011-01-01T14:23:14',8 union all
- select 1,'2011-01-01T14:23:15',7 union all
- select 1,'2011-01-01T14:23:17',4 union all
- select 1,'2011-01-01T14:23:18',2
- ;with StartPeriods as (
- select m1.DeviceID,m1.Occurred as Started
- from Measures m1 left join Measures m2 on m1.DeviceID = m2.DeviceID and m2.Occurred < m1.Occurred and DATEDIFF(second,m2.Occurred,m1.Occurred) < 6
- where m2.DeviceID is null
- ), ExtendPeriods as (
- select DeviceID,Started,Started as Ended from StartPeriods
- union all
- select
- ep.DeviceID,ep.Started,m2.Occurred
- from
- ExtendPeriods ep
- inner join
- Measures m2
- on
- ep.DeviceID = m2.DeviceID and
- ep.Ended < m2.Occurred and
- DATEDIFF(SECOND,ep.Ended,m2.Occurred) < 6
- )
- select DeviceID,Started,MAX(Ended) from ExtendPeriods group by DeviceID,Started
- select DeviceID,MIN(Timestamp),MAX(Timestamp)
- from @table group by DATEPART(hh,Timestamp),DeviceID
- WITH data (DeviceID, Timestamp, Value) AS (
- SELECT 'Device1', CAST('1.1.2011 10:00:00' AS datetime), 3 UNION ALL
- SELECT 'Device1', '1.1.2011 10:00:01', 4 UNION ALL
- SELECT 'Device1', '1.1.2011 10:00:02', 4 UNION ALL
- SELECT 'Device1', '1.1.2011 10:00:04', 3 UNION ALL
- SELECT 'Device1', '1.1.2011 10:00:05', 4 UNION ALL
- SELECT 'Device1', '1.1.2011 14:23:14', 8 UNION ALL
- SELECT 'Device1', '1.1.2011 14:23:15', 7 UNION ALL
- SELECT 'Device1', '1.1.2011 14:23:17', 4 UNION ALL
- SELECT 'Device1', '1.1.2011 14:23:18', 2
- ),
- ranked AS (
- SELECT
- *,
- rn = ROW_NUMBER() OVER (PARTITION BY DeviceID ORDER BY Timestamp)
- FROM data
- ),
- starts AS (
- SELECT
- r1.DeviceID,
- r1.Timestamp,
- rank = ROW_NUMBER() OVER (PARTITION BY r1.DeviceID ORDER BY r1.Timestamp)
- FROM ranked r1
- LEFT JOIN ranked r2 ON r1.DeviceID = r2.DeviceID
- AND r1.rn = r2.rn + 1
- AND r1.Timestamp <= DATEADD(second, 5, r2.Timestamp)
- WHERE r2.DeviceID IS NULL
- ),
- ends AS (
- SELECT
- r1.DeviceID,
- r1.Timestamp,
- rank = ROW_NUMBER() OVER (PARTITION BY r1.DeviceID ORDER BY r1.Timestamp)
- FROM ranked r1
- LEFT JOIN ranked r2 ON r1.DeviceID = r2.DeviceID
- AND r1.rn = r2.rn - 1
- AND r1.Timestamp >= DATEADD(second, -5, r2.Timestamp)
- WHERE r2.DeviceID IS NULL
- )
- SELECT
- s.DeviceID,
- Started = s.Timestamp,
- Ended = e.Timestamp
- FROM starts s
- INNER JOIN ends e ON s.DeviceID = e.DeviceID AND s.rank = e.rank
- SELECT a.TS AS [StartTime], (SELECT TOP 1 c.TS FROM TestTime c WHERE c.TS >= a.TS AND
- NOT EXISTS(SELECT * FROM TestTime d WHERE d.TS > c.TS AND DATEDIFF(SECOND, c.TS, d.TS) <= 5) ORDER BY c.TS) AS [StopTime]
- FROM TestTime a WHERE NOT EXISTS (SELECT * FROM TestTime b WHERE a.TS > b.TS AND DATEDIFF(SECOND, b.TS, a.TS) <= 5)
- DECLARE @t TABLE
- (DeviceID VARCHAR(10),
- [Timestamp] DATETIME,
- VALUE INT
- )
- INSERT @t
- SELECT 'Device1','20110101 10:00:00', 3
- UNION SELECT 'Device1','20110101 10:00:01', 4
- UNION SELECT 'Device1','20110101 10:00:02', 4
- UNION SELECT 'Device1','20110101 10:00:04', 3
- UNION SELECT 'Device1','20110101 10:00:05', 4
- UNION SELECT 'Device1','20110101 14:23:14', 8
- UNION SELECT 'Device1','20110101 14:23:15', 7
- UNION SELECT 'Device1','20110101 14:23:17', 4
- UNION SELECT 'Device1','20110101 14:23:18', 2
- ;WITH myCTE
- AS
- (
- SELECT DeviceID, [Timestamp],
- ROW_NUMBER() OVER (PARTITION BY DeviceID
- ORDER BY [TIMESTAMP]
- ) AS rn
- FROM @t
- )
- , recCTE
- AS
- (
- SELECT DeviceID, [Timestamp], 0 as groupID, rn FROM myCTE
- WHERE rn = 1
- UNION ALL
- SELECT r.DeviceID, g.[Timestamp], CASE WHEN DATEDIFF(ss,r.[Timestamp], g.[Timestamp]) <= 5 THEN r.groupID ELSE r.groupID + 1 END, g.rn
- FROM recCTE AS r
- JOIN myCTE AS g
- ON g.rn = r.rn + 1
- )
- SELECT DeviceID, MIN([Timestamp]) AS [started], MAX([Timestamp]) AS ended
- FROM recCTE
- GROUP BY DeviceId, groupId
- OPTION (MAXRECURSION 0);
- SELECT DeviceId,
- Timestamp,
- COALESCE((Timestamp - lag(Timestamp) OVER w) > interval '15 min', TRUE)
- as session_begins
- COALESCE((lead(Timestamp) OVER w - Timestamp) > interval '15 min', TRUE)
- as session_ends
- FROM YourTable
- WINDOW w AS (PARTITION BY DeviceId ORDER BY Timestamp);