Reputation: 25
My GPS table in postgres has the schema with four fields as userid (int), latitude (float8), longitude (float8), recordedtime (time stamp). For every user, we get 2 records for every minute.
Need a query to find the users who spent more then 15 minutres in same GPS lat long value?
the sample records could be
Userid, Latitiude, Longitude, recordedtime
============================================
'ID1',12.089475408,76.089890,2019-11-24 19:10:01
'ID1',12.089475408,76.089890,2019-11-24 19:10:31
'ID1',12.089475408,76.089890,2019-11-24 19:11:01
'ID1',12.089475408,76.089890,2019-11-24 19:10:31
'ID1',12.089475408,76.089890,2019-11-24 19:12:01
'ID1',12.089475408,76.089890,2019-11-24 19:10:31
....
..
Could anyone please provide the required query?
Upvotes: 1
Views: 367
Reputation: 19623
This CTE
might be what you're looking for.
WITH j AS (
SELECT userid,longitude,latitude,
max(recordedtime)-min(recordedtime) AS timespent
FROM t
GROUP BY userid,longitude,latitude
) SELECT * FROM j
WHERE timespent > interval '15 minute';
userid | longitude | latitude | timespent
--------+-----------+-----------+-----------
ID1 | 80.205480 | 13.082240 | 00:20:00
(1 Zeile)
Have you considered using PostGIS
to deal with your points? Your use case seems pretty simple, but very quickly you might find yourself struggling to perform geospatial operations in your data model that are already solved in PostGIS.
In case you're interested, this is what you should do to create a geometry column based on your GPS coordinates:
ALTER TABLE t ADD COLUMN geom GEOMETRY;
UPDATE t SET geom = ST_SetSRID(ST_MakePoint(longitude, latitude),4326);
The value 4326 in the ST_SetSRID
function stands for the Reference System WGS84. Check which one suits your coordinates.
And this is how the query would look like:
WITH j AS (
SELECT userid,geom,
max(recordedtime)-min(recordedtime) AS timespent
FROM t
GROUP BY userid,geom
) SELECT userid,ST_AsText(geom),timespent FROM j
WHERE timespent > interval '15 minute';
userid | st_astext | timespent
--------+--------------------------+-----------
ID1 | POINT(80.20548 13.08224) | 00:20:00
(1 Zeile)
Note: As mentioned by @JGH, this use case assumes that the coordinates are identical in order to compute the time spent in certain location. Your coordinates have six decimal places, which gives you a precision of 0.111 m
. Long story short, if the coordinates deviate by a few meters it won't work. In PostGIS using ST_Buffer
you can easily create a buffer of a given size and with ST_Within
you can check if one of your points is inside of the buffer. The query below should give an idea on how to do this:
(Buffer of 50 meters)
WITH j AS (
SELECT userid, recordedtime, geom,
ST_Buffer(geom::GEOGRAPHY,50)::GEOMETRY AS buffer
FROM t
) SELECT t.userid, max(t.recordedTime)-min(t.recordedTime) AS timespent
FROM t,j
WHERE t.userid=j.userid AND ST_Within(t.geom,j.buffer)
GROUP BY t.userid
HAVING max(t.recordedTime)-min(t.recordedTime) > INTERVAL '15 minute';
userid | timespent
--------+-----------
ID1 | 00:22:00
(1 Zeile)
Upvotes: 2