What is the best way to perform an SQL query to return all records where there is not another record with a matching id and a timestamp within X time?
So, for example, given the database table sample below and a timeframe of 5 hours, I would want the query to return the sample result.
Sample Data:
id | timestamp
01 | 2015-08-03 03:00:00
01 | 2015-08-03 14:00:00
01 | 2015-08-03 15:00:00
01 | 2015-08-03 16:00:00
02 | 2015-08-03 4:00:00
02 | 2015-08-03 5:00:00
03 | 2015-08-03 2:00:00
03 | 2015-08-03 5:00:00
03 | 2015-08-03 10:01:00
Sample Result:
01 | 2015-08-03 03:00:00
01 | 2015-08-03 16:00:00
02 | 2015-08-03 5:00:00
03 | 2015-08-03 5:00:00
03 | 2015-08-03 10:01:00
...since these are the only records for their respective ids where no other records with matching ids occur in the following 5 hours.
My current solution is to essentially query the entire table and then loop through each record querying on a local datatable. It works but is highly inefficient. Is there an SQL way of doing this? I have looked around for awhile, and I am coming up short. But, I might just not be searching correctly. There is probably some simple solution that I am missing, but I am still pretty new to SQL.
Thanks!
Update:
I should have included the current query I am using for reference. Note that "id" in the sample above really refers to "deviceid" in my actual query. It is:
SELECT id AS 'ID',
eventsink.elevatortripevent.deviceid AS 'DeviceID',
completed AS 'Created',
digitalposition AS 'DigitalPosition',
buildingstate AS 'State'
FROM eventsink.elevatortripevent
JOIN md.elevator
ON md.elevator.deviceid = eventsink.elevatortripevent.deviceid
JOIN ea.elevatoreventevent
ON ea.elevatoreventevent.deviceid =
eventsink.elevatortripevent.deviceid
WHERE completed >= '8/2/2016 8:13:34 PM'
AND completed <= '8/3/2016 8:13:34 PM'
ORDER BY eventsink.elevatortripevent.deviceid
Attempt at Implementing Answer by @irimias
SELECT id AS 'ID',
trip1.deviceid AS 'Device ID',
trip1.completed AS 'Created',
digitalposition AS 'Digital Position',
buildingstate AS 'State'
FROM eventsink.elevatortripevent trip1
LEFT JOIN eventsink.elevatortripevent trip2
ON trip1.deviceid = trip2.deviceid
AND trip1.completed < trip2.completed
AND trip1.completed > Dateadd(hh, -5, trip2.completed)
JOIN md.elevator
ON md.elevator.deviceid = trip1.deviceid
JOIN ea.elevatoreventevent
ON ea.elevatoreventevent.deviceid = trip1.deviceid
WHERE trip2.deviceid IS NULL
AND trip1.completed >= '8/2/2016 8:13:34 PM'
AND trip1.completed <= '8/3/2016 8:13:34 PM'
ORDER BY trip1.deviceid
Attempt at Implementing Answer by @dnoeth
WITH cte
AS (SELECT eventsink.elevatortripevent.deviceid,
completed,
Lead(completed)
OVER (
partition BY eventsink.elevatortripevent.deviceid
ORDER BY completed) AS nextTS
FROM eventsink.elevatortripevent)
SELECT id AS 'ID',
cte.deviceid AS 'DeviceID',
completed AS 'Created',
digitalposition AS 'DigitalPosition',
buildingstate AS 'State'
FROM cte
JOIN md.elevator
ON md.elevator.deviceid = cte.deviceid
JOIN ea.elevatoreventevent
ON ea.elevatoreventevent.deviceid =
cte.deviceid
WHERE ( nextts IS NULL
OR completed < Dateadd(hh, -5, nextts) )
AND completed >= '8/2/2016 8:13:34 PM'
AND completed <= '8/3/2016 8:13:34 PM'
ORDER BY cte.deviceid