I want to calculate the difference between a status change, however the same state can have multiple records, see example below.
create table #DeviceMessages
(
DoorName nvarchar(50),
[StatusDoor] nvarchar(50),
EventEndDate DatetIme
)
INSERT INTO #DeviceMessages
(DoorName, [StatusDoor], EventEndDate)
VALUES
('Door 001', 'OPEN', '2017-03-23 16:50:42.143'),
('Door 001', 'CLOSED','2017-03-23 16:54:15.813'),
('Door 001', 'CLOSED','2017-03-23 17:53:12.757'),
('Door 001', 'OPEN', '2017-03-23 18:22:37.560'),
('Door 001', 'CLOSED','2017-03-23 18:28:01.197'),
('Door 001', 'CLOSED','2017-03-23 18:28:01.250'),
('Door 001', 'OPEN', '2017-03-23 18:29:40.593'),
('Door 001', 'OPEN', '2017-03-23 18:29:40.600'),
('Door 001', 'CLOSED','2017-03-23 18:34:53.827'),
('Door 001', 'CLOSED','2017-03-23 18:34:53.843'),
('Door 001', 'OPEN', '2017-03-23 18:42:56.463'),
('Door 001', 'OPEN', '2017-03-23 18:42:56.470'),
('Door 001', 'CLOSED','2017-03-23 18:46:32.550');
GO
It goes well when there are multiple CLOSED records, but it doesn't work when there are multiple OPEN records. At that moment I want the earliest OPEN record, compared to the nearest CLOSED record. I use the following statement:
WITH DoorActivityWPairedTimes
AS
(SELECT [StatusDoor]
, EventEndDate
, DeviceDoorOpen = DoorName
, DeviceDoorClosed = LEAD(DoorName, 1) OVER(ORDER BY DoorName, EventEndDate)
, DoorOpen = EventEndDate
, DoorClosed = LEAD(EventEndDate, 1) OVER(ORDER BY DoorName, EventEndDate)
, DoorOpenActivityDate = CAST(EventEndDate AS DATE)
, DoorDichtActivityDate = CAST(LEAD(EventEndDate, 1) OVER(ORDER BY DoorName, EventEndDate) AS DATE)
FROM #DeviceMessages)
SELECT DeviceDoorOpen Device
, EventEndDate
, DoorOpen
, DoorClosed
, DATEDIFF(second, DoorOpen, DoorClosed) DurationOpenSec
FROM DoorActivityWPairedTimes
WHERE [StatusDoor] = 'OPEN'
AND DoorOpen Is Not Null
AND DeviceDoorOpen = DeviceDoorClosed
AND DoorDichtActivityDate = DoorOpenActivityDate
order by EventEndDate asc
The result of the query above:
+----------+-------------------------+-------------------------+-------------+
| Device | DoorOpen | DoorClosed | Dur.OpenSec |
+----------+-------------------------+-------------------------+-------------+
| Door 001 | 2017-03-23 16:50:42.143 | 2017-03-23 16:54:15.813 | 213 |
| Door 001 | 2017-03-23 18:22:37.560 | 2017-03-23 18:28:01.197 | 324 |
| Door 001 | 2017-03-23 18:29:40.593 | 2017-03-23 18:29:40.600 | 0 |
| Door 001 | 2017-03-23 18:29:40.600 | 2017-03-23 18:34:53.827 | 313 |
| Door 001 | 2017-03-23 18:42:56.463 | 2017-03-23 18:42:56.470 | 0 |
| Door 001 | 2017-03-23 18:42:56.470 | 2017-03-23 18:46:32.550 | 216 |
+----------+-------------------------+-------------------------+-------------+
WANTED RESULT
+----------+-------------------------+-------------------------+-------------+
| Device | DoorOpen | DoorClosed | Dur.OpenSec |
+----------+-------------------------+-------------------------+-------------+
| Door 001 | 2017-03-23 16:50:42.143 | 2017-03-23 16:54:15.813 | 213 |
| Door 001 | 2017-03-23 18:22:37.560 | 2017-03-23 18:28:01.197 | 324 |
| Door 001 | 2017-03-23 18:29:40.593 | 2017-03-23 18:34:53.827 | 313 |
| Door 001 | 2017-03-23 18:42:56.463 | 2017-03-23 18:46:32.550 | 216 |
+----------+-------------------------+-------------------------+-------------+
Can some helpme to make a query that makes the wanted result?
Best Answer
IMHO this question can be solved using a classic GROUPING AND WINDOWS solution.
Reset point
According to your question:
Two or more contiguous CLOSED records, require two different groups.
I've a set a reset point when:
In addition, I've added a
MinMaxOrder
just to ensure OPEN events can be fetched before CLOSED events.As far as each CLOSED event produces a new group, I can get MIN and MAX event of each group, and return only those groups with more than one record.
dbfiddle here