Question

I have two tables:

  • Locations - stores a user's geographical location and the timestamp.
  • Events - stores an event's geographical bounds and the start and end time of a rock concert event.

Is there a query that will get the start and end time of all users at events?

Here's a sample of the data:

CREATE TABLE locations (
  user_id INT NOT NULL,
  timestamp DATETIME NOT NULL,
  latitude FLOAT NOT NULL,
  longitude FLOAT NOT NULL
);

INSERT INTO locations (user_id, timestamp, latitude, longitude)
VALUES
  (1, '2013-11-22 01:12:23', 37.7674, -122.439),
  (1, '2013-11-22 01:13:24', 37, -122),
  (1, '2013-11-22 01:14:25', 37.7674, -122.439),
  (2, '2013-11-25 01:12:23', 37.7674, -122.439),
  (2, '2013-11-25 01:13:24', 37, -122),
  (2, '2013-11-25 01:14:25', 37.7674, -122.439);

CREATE TABLE events (
  event_id INT NOT NULL,
  begin_time DATETIME NOT NULL,
  end_time DATETIME NOT NULL,
  min_latitude FLOAT NOT NULL,
  max_latitude FLOAT NOT NULL,
  min_longitude FLOAT NOT NULL,
  max_longitude FLOAT NOT NULL
);

INSERT INTO events (event_id, begin_time, end_time, min_latitude, max_latitude, min_longitude, max_longitude)
VALUES
  (1, '2013-11-22 01:00:00', '2013-11-22 02:00:00', 37.7673, 37.7675, -122.440, -122.439),
  (2, '2013-11-25 01:00:00', '2013-11-25 02:00:00', 37.7674, 37.7674, -122.439, -122.439);

The problem has two parts:

  • The first part involves finding all the rows where users were at events.
  • The second part involves finding the first timestamp where the user entered the event (then ignore all the subsequent rows where the user remains at the event) then get the row where the user left the event. This would be easy if we just get all rows where the user was inside the event.

The following would give me all rows where the user's location coincides with an event.

select * from locations
join events on 
locations.timestamp between events.begin_time    and events.end_time     and
locations.latitude  between events.min_latitude  and events.max_latitude and
locations.longitude between events.min_longitude and events.max_longitude 

However, I can't seem to figure out a good way to get only the begin and end times of a user at an event. Also, (I don't know if this makes the problem more interesting) it's possible for users to leave and return to the same event.

(I'm using MySQL, but I'll accept answers in any flavor of SQL.)

Was it helpful?

Solution

Try this one - i think you can get what you want from it. I used a temp table, which you could avoid in one of several ways if you want to, but I think it makes it easier to visualize. I can think of some optimizations as well, but this will work fine for a dataset that isn't too massive. There may also be some boundary conditions I'm not thinking of. Okay, can I qualify my answer any more. . .

--1.Get into temp table
 select e.event_id, l.user_id,l.timestamp into #temp from locations l
left join events e on l.timestamp between e.begin_time and e.end_time 
and l.latitude between e.min_latitude and e.max_latitude 
and l.longitude between e.min_longitude and e.max_longitude 

--2.Get when entered and left event
Select t1.*,
CASE WHEN t1.event_id is not null and isnull(t2.event_id,0)<>t1.event_id
   THEN 'Yes' ELSE 'No' END As EnteredEvent,
CASE WHEN isnull(t1.event_id,0)<>isnull(t2.event_id,-1) and t2.event_id is not null
   THEN 'Yes' ELSE 'No' END As LeftEvent
 from 
(SELECT  t1.*, (
        SELECT  max(timestamp) as t22
        FROM    #temp t2
        WHERE   t1.user_id=t2.user_id and t2.timestamp < t1.timestamp
        ) as priortimestamp
FROM #temp t1) as t1
LEFT JOIN #temp t2 ON t1.user_id=t2.user_id and t1.priortimestamp=t2.timestamp
ORDER BY  t1.user_id, t1.timestamp,t1.event_id

Hope this helps

OTHER TIPS

Can you try this query,

select user_id, MIN(timestamp) as enteredtime, MAX(timestamp) as exittime 
from 
locations
join 
events 
on 
locations.timestamp between events.begin_time and events.end_time 
and
locations.latitude  between events.min_latitude  and events.max_latitude 
and
locations.longitude between events.min_longitude and events.max_longitude 
GROUP BY locations.user_id

You can see the demo at http://sqlfiddle.com/#!2/e8ba2/1, hope it is helpful

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top