patternsqlMinor
Get start time and end time of a trip in SQL Server
Viewed 0 times
serversqlstarttimegettripendand
Problem
I have a table that contains zone in and out information about a bus, and its structure is like this:
id zoneid status datetime
1 35 IN 2016-02-02 11:36:39
2 35 OUT 2016-02-02 11:36:59
3 36 IN 2016-02-02 11:37:35
4 36 IN 2016-02-02 11:37:49
5 36 OUT 2016-02-02 11:38:06
6 38 IN 2016-02-02 11:39:37
7 38 OUT 2016-02-02 11:39:55
8 38 OUT 2016-02-02 11:40:09
9 36 IN 2016-02-02 11:41:39
10 36 OUT 2016-02-02 11:41:49
11 35 IN 2016-02-02 11:42:01
12 35 IN 2016-02-02 11:42:13
13 35 IN 2016-02-02 11:42:28
14 35 OUT 2016-02-02 11:42:39
15 36 IN 2016-02-02 11:42:49
16 36 IN 2016-02-02 11:43:03
17 36 OUT 2016-02-02 11:43:19
18 38 IN 2016-02-02 11:44:00
19 38 OUT 2016-02-02 11:44:18
20 38 OUT 2016-02-02 11:44:39
21 36 IN 2016-02-02 11:45:20
22 36 OUT 2016-02-02 11:45:43
23 35 IN 2016-02-02 11:46:00
24 35 IN 2016-02-02 11:46:04
Zone 35 and 38 are the edge point of a trip. When a bus gets out from zone 35, first trip starts, and when it enters zone 38, first trip ends. After that, whenever it gets out of zone 38, second trip starts, and when it enters zone 35, second trip ends. This process goes on. What I actually need is to get the start time and end time of a trip. According to the data in table, the result should be:
starttime endtime
2016-02-02 11:36:59 2016-02-02 11:39:37
2016-02-02 11:39:55 2016-02-02 11:42:01
2016-02-02 11:42:39 2016-02-02 11:44:00
2016-02-02 11:44:18 2016-02-02 11:46:00
Any suggestions? Thanks in advance.
id zoneid status datetime
1 35 IN 2016-02-02 11:36:39
2 35 OUT 2016-02-02 11:36:59
3 36 IN 2016-02-02 11:37:35
4 36 IN 2016-02-02 11:37:49
5 36 OUT 2016-02-02 11:38:06
6 38 IN 2016-02-02 11:39:37
7 38 OUT 2016-02-02 11:39:55
8 38 OUT 2016-02-02 11:40:09
9 36 IN 2016-02-02 11:41:39
10 36 OUT 2016-02-02 11:41:49
11 35 IN 2016-02-02 11:42:01
12 35 IN 2016-02-02 11:42:13
13 35 IN 2016-02-02 11:42:28
14 35 OUT 2016-02-02 11:42:39
15 36 IN 2016-02-02 11:42:49
16 36 IN 2016-02-02 11:43:03
17 36 OUT 2016-02-02 11:43:19
18 38 IN 2016-02-02 11:44:00
19 38 OUT 2016-02-02 11:44:18
20 38 OUT 2016-02-02 11:44:39
21 36 IN 2016-02-02 11:45:20
22 36 OUT 2016-02-02 11:45:43
23 35 IN 2016-02-02 11:46:00
24 35 IN 2016-02-02 11:46:04
Zone 35 and 38 are the edge point of a trip. When a bus gets out from zone 35, first trip starts, and when it enters zone 38, first trip ends. After that, whenever it gets out of zone 38, second trip starts, and when it enters zone 35, second trip ends. This process goes on. What I actually need is to get the start time and end time of a trip. According to the data in table, the result should be:
starttime endtime
2016-02-02 11:36:59 2016-02-02 11:39:37
2016-02-02 11:39:55 2016-02-02 11:42:01
2016-02-02 11:42:39 2016-02-02 11:44:00
2016-02-02 11:44:18 2016-02-02 11:46:00
Any suggestions? Thanks in advance.
Solution
My idea for this is ,first, to filter only the records with
Then base on this, give me the next record(most near the the record as datetime)that have different
(Ex:If I have 35 and OUT , give me the next 38 and IN.)
And I added a additional condition.The
I have the next output:
zoneID 35 or 38 that have have status = OUT (this mean the start of the trip)Then base on this, give me the next record(most near the the record as datetime)that have different
zoneID and different status (Ex:If I have 35 and OUT , give me the next 38 and IN.)
And I added a additional condition.The
previous zoneID (LAG) of the current zoneID are different DECLARE @Table1 TABLE
([id] int, [zoneid] int, [status] varchar(3), [datetime] datetime);
INSERT INTO @Table1
([id], [zoneid], [status], [datetime])
VALUES
(1, 35, 'IN', '2016-02-02 11:36:39'),
(2, 35, 'OUT', '2016-02-02 11:36:59'),
(3, 36, 'IN', '2016-02-02 11:37:35'),
(4, 36, 'IN', '2016-02-02 11:37:49'),
(5, 36, 'OUT', '2016-02-02 11:38:06'),
(6, 38, 'IN', '2016-02-02 11:39:37'),
(7, 38, 'OUT', '2016-02-02 11:39:55'),
(8, 38, 'OUT', '2016-02-02 11:40:09'),
(9, 36, 'IN', '2016-02-02 11:41:39'),
(10, 36, 'OUT', '2016-02-02 11:41:49'),
(11, 35, 'IN', '2016-02-02 11:42:01'),
(12, 35, 'IN', '2016-02-02 11:42:13'),
(13, 35, 'IN', '2016-02-02 11:42:28'),
(14, 35, 'OUT', '2016-02-02 11:42:39'),
(15, 36, 'IN', '2016-02-02 11:42:49'),
(16, 36, 'IN', '2016-02-02 11:43:03'),
(17, 36, 'OUT', '2016-02-02 11:43:19'),
(18, 38, 'IN', '2016-02-02 11:44:00'),
(19, 38, 'OUT', '2016-02-02 11:44:18'),
(20, 38, 'OUT', '2016-02-02 11:44:39'),
(21, 36, 'IN', '2016-02-02 11:45:20'),
(22, 36, 'OUT', '2016-02-02 11:45:43'),
(23, 35, 'IN', '2016-02-02 11:46:00'),
(24, 35, 'IN', '2016-02-02 11:46:04');
SELECT
[id]
,starttime
,endtime
FROM
(
SELECT
T1.[id]
,T1.[zoneid]
,T1.[status]
,T1.[datetime] AS starttime
,CA.[datetime] AS endtime
,LAG(T1.[zoneid],1,1) OVER(ORDER BY T1.[id]) AS PrevZoneID
FROM
@Table1 AS T1
CROSS APPLY
(
SELECT TOP(1)
T2.[id], T2.[zoneid], T2.[status], T2.[datetime]
FROM
@Table1 AS T2
WHERE
T1.[zoneid] <> T2.[zoneid] --give the other zone
AND T1.[status] <> T2.[status] -- different status
AND (T2.[zoneid] = 35 OR T2.[zoneid] = 38)
AND T1.[datetime] A.[zoneid];I have the next output:
id starttime endtime
2 2016-02-02 11:36:59.000 2016-02-02 11:39:37.000
7 2016-02-02 11:39:55.000 2016-02-02 11:42:01.000
14 2016-02-02 11:42:39.000 2016-02-02 11:44:00.000
19 2016-02-02 11:44:18.000 2016-02-02 11:46:00.000Code Snippets
DECLARE @Table1 TABLE
([id] int, [zoneid] int, [status] varchar(3), [datetime] datetime);
INSERT INTO @Table1
([id], [zoneid], [status], [datetime])
VALUES
(1, 35, 'IN', '2016-02-02 11:36:39'),
(2, 35, 'OUT', '2016-02-02 11:36:59'),
(3, 36, 'IN', '2016-02-02 11:37:35'),
(4, 36, 'IN', '2016-02-02 11:37:49'),
(5, 36, 'OUT', '2016-02-02 11:38:06'),
(6, 38, 'IN', '2016-02-02 11:39:37'),
(7, 38, 'OUT', '2016-02-02 11:39:55'),
(8, 38, 'OUT', '2016-02-02 11:40:09'),
(9, 36, 'IN', '2016-02-02 11:41:39'),
(10, 36, 'OUT', '2016-02-02 11:41:49'),
(11, 35, 'IN', '2016-02-02 11:42:01'),
(12, 35, 'IN', '2016-02-02 11:42:13'),
(13, 35, 'IN', '2016-02-02 11:42:28'),
(14, 35, 'OUT', '2016-02-02 11:42:39'),
(15, 36, 'IN', '2016-02-02 11:42:49'),
(16, 36, 'IN', '2016-02-02 11:43:03'),
(17, 36, 'OUT', '2016-02-02 11:43:19'),
(18, 38, 'IN', '2016-02-02 11:44:00'),
(19, 38, 'OUT', '2016-02-02 11:44:18'),
(20, 38, 'OUT', '2016-02-02 11:44:39'),
(21, 36, 'IN', '2016-02-02 11:45:20'),
(22, 36, 'OUT', '2016-02-02 11:45:43'),
(23, 35, 'IN', '2016-02-02 11:46:00'),
(24, 35, 'IN', '2016-02-02 11:46:04');
SELECT
[id]
,starttime
,endtime
FROM
(
SELECT
T1.[id]
,T1.[zoneid]
,T1.[status]
,T1.[datetime] AS starttime
,CA.[datetime] AS endtime
,LAG(T1.[zoneid],1,1) OVER(ORDER BY T1.[id]) AS PrevZoneID
FROM
@Table1 AS T1
CROSS APPLY
(
SELECT TOP(1)
T2.[id], T2.[zoneid], T2.[status], T2.[datetime]
FROM
@Table1 AS T2
WHERE
T1.[zoneid] <> T2.[zoneid] --give the other zone
AND T1.[status] <> T2.[status] -- different status
AND (T2.[zoneid] = 35 OR T2.[zoneid] = 38)
AND T1.[datetime] < T2.[datetime]
ORDER BY
T2.[datetime] ASC
)CA
WHERE
(T1.[zoneid] = 35 AND T1.[status] = 'OUT')
OR (T1.[zoneid] = 38 AND T1.[status] = 'OUT')
)A
WHERE
A.PrevZoneID <> A.[zoneid];id starttime endtime
2 2016-02-02 11:36:59.000 2016-02-02 11:39:37.000
7 2016-02-02 11:39:55.000 2016-02-02 11:42:01.000
14 2016-02-02 11:42:39.000 2016-02-02 11:44:00.000
19 2016-02-02 11:44:18.000 2016-02-02 11:46:00.000Context
StackExchange Database Administrators Q#128106, answer score: 2
Revisions (0)
No revisions yet.