Reputation: 69
Simplified structure.
I need the two dates between a record that has an action type of 4 and an action type of 1.
The record could be in that state multiple times and I would need separate rows for their times
For example for IncidentId = 1
CREATE TABLE #returntable ( [incidentid] INT, [starttime] DATETIME, [endtime] DATETIME ) CREATE TABLE #testtableofdoom ( [incidentlogid] INT, [incidentid] INT, [timestamp] DATETIME, [actiontypeid] INT ) INSERT INTO #testtableofdoom ( incidentlogid, incidentid, timestamp, actiontypeid ) VALUES ( 1, 1, '2017-01-01 09:00', 1 ) , ( 2, 1, '2017-01-01 11:00', 1 ) , ( 3, 1, '2017-01-01 14:00', 4 ) , ( 4, 1, '2017-01-01 16:00', 4 ) , ( 5, 1, '2017-01-01 20:00', 1 ) , ( 6, 1, '2017-01-01 21:00', 4 ) , ( 7, 1, '2017-01-02 09:00', 4 ) , ( 8, 2, '2017-01-02 10:00', 1 ) , ( 9, 1, '2017-01-02 11:00', 1 ) , ( 10, 1, '2017-01-02 14:00', 1 ) , ( 11, 2, '2017-01-02 15:00', 4 ) , ( 12, 1, '2017-01-02 16:00', 1 ) , ( 13, 1, '2017-01-02 17:00', 1 ) , ( 14, 1, '2017-01-02 18:00', 1 ) , ( 15, 2, '2017-01-02 15:00', 1 ); DROP TABLE #testtableofdoom DROP TABLE #returntable
Upvotes: 1
Views: 2246
Reputation: 146597
I used table variables instead of temp tables, and shorter column names than you, but this works:
declare @tt TABLE (
logId INT, iId INT,
dt DATETIME, atId INT
INSERT @tt (logId, iId,
dt, atId) values
(1, 1, '2017-01-01 09:00', 1),
(2, 1, '2017-01-01 11:00', 1),
(3, 1, '2017-01-01 14:00', 4),
(4, 1, '2017-01-01 16:00', 4),
(5, 1, '2017-01-01 20:00', 1),
(6, 1, '2017-01-01 21:00', 4),
(7, 1, '2017-01-02 09:00', 4),
(8, 2, '2017-01-02 10:00', 1),
(9, 1, '2017-01-02 11:00', 1),
(10, 1, '2017-01-02 14:00', 1),
(11, 2, '2017-01-02 15:00', 4),
(12, 1, '2017-01-02 16:00', 1),
(13, 1, '2017-01-02 17:00', 1),
(14, 1, '2017-01-02 18:00', 1),
(15, 2, '2017-01-02 15:00', 1)
Select s.logId startLogid, e.logId endLogId,
s.iID, s.dt startTime, e.dt endTime
from @tt s join @tt e
on e.logId =
(Select min(logId) from @tt
where iId = s.iID
and atId = 1
and logId > s.logId)
where s.aTid = 4
and ((Select atId from @tt
Where logId =
(Select Max(logId) from @tt
where logId < s.LogId
and iId = s.iId)) = 1
or Not Exists
(Select * from @tt
Where logId < s.LogId
and iId = s.iID))
This produces the following:
startLogid endLogId iID startTime endTime
----------- ----------- ---- ---------------- ----------------
3 5 1 2017-01-01 14:00 2017-01-01 20:00
6 9 1 2017-01-01 21:00 2017-01-02 11:00
11 15 2 2017-01-02 15:00 2017-01-02 15:00
it uses a self-join. s
represents the first (start) record with actionType 4, and e
represents end record with action type 1. Since logId
increments, the end record must have higher logId
than the start record, and it must be the lowest logId
higher than the start records that has same iId
and an atId
= 1.
Select s.iID, s.dt startTime, e.dt endTime
from @tt s join @tt e
on e.logId =
(Select min(logId) from @tt -- lowest log greater than start logId
where iId = s.iID -- same iId
and atId = 1 -- with atId = 1
and logId > s.logId) -- greater than start logId
finally, the start record must be restricted to those "4" records which either have no other same incident records before it or have a "1" record immediately prior to it.
where s.aTid = 4
and ((Select atId from @tt -- atId of immed prior = 1
Where logId =
(Select Max(logId) from @tt
where logId < s.LogId
and iId = s.iId)) = 1
or Not Exists -- or there is no prior record
(Select * from @tt
Where logId < s.LogId
and iId = s.iID))
Upvotes: 2
Reputation: 299
something like this?
select
d.[timestamp] as StartDate,
(select top 1 [timestamp]
from #testTableOfDoom d2
where d2.incidentid = 1 and d2.[timestamp] > d.[timestamp] and actiontypeid = 1
order by d2.[timestamp] asc
) as EndDate
from
(select
p.[timestamp],
LAG(p.actiontypeid) OVER (ORDER BY incidentlogid asc) PrevValue,
p.actiontypeid
from #testTableOfDoom p
where p.incidentid = 1) d
where d.actiontypeid = 4
and d.PrevValue <> 4
Upvotes: 1