SQL-запрос, чтобы получить только время начала и окончания события

У меня есть две таблицы:

  • Locations — хранит географическое местоположение пользователя и метку времени.
  • События — хранит географические границы события, а также время начала и окончания рок-концерта.

Есть ли запрос, который будет получать время начала и окончания всех пользователей на мероприятиях?

Вот пример данных:

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);

Проблема состоит из двух частей:

  • Первая часть включает в себя поиск всех строк, в которых пользователи были на событиях.
  • Вторая часть включает в себя поиск первой метки времени, в которой пользователь вошел в событие (затем игнорируются все последующие строки, в которых пользователь остается в событии), а затем получение строки, в которой пользователь покинул событие. Это было бы легко, если бы мы просто получили все строки, в которых пользователь находился внутри события.

Следующее даст мне все строки, в которых местоположение пользователя совпадает с событием.

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 

Однако я не могу найти хороший способ получить только время начала и окончания пользователя на мероприятии. Кроме того, (я не знаю, делает ли это проблему более интересной) пользователи могут уйти и вернуться к одному и тому же событию.

(Я использую MySQL, но приму ответы на любом варианте SQL.)


person Glenn    schedule 26.11.2013    source источник
comment
Пробовали ли вы группировать по user_id и event_id и выбирать min(timestamp) и max(timestamp)?   -  person acfrancis    schedule 26.11.2013
comment
Да, и спасибо за ваше предложение. К сожалению, это не справится со случаем, когда пользователь уходит и возвращается к одному и тому же событию. Я хотел бы знать, когда они ушли и вернулись на мероприятие, чтобы мы не выставляли им счета за эти часы.   -  person Glenn    schedule 26.11.2013
comment
Откуда ты знаешь, что они ушли и вернулись? В ваших таблицах этого не видно.   -  person acfrancis    schedule 26.11.2013
comment
Да, и прошу прощения, если что-то непонятно. Когда мы упорядочиваем таблицу locations по метке времени, если latitude, longitude когда-либо находится в пределах events, а затем выходит за пределы events, и наоборот. Мы можем определить, что пользователь ушел и вернулся к событию. Спасибо.   -  person Glenn    schedule 26.11.2013
comment
Это звучит как проблема «пробелов и островов». Поможет ли вам какой-либо из этих похожих вопросов?   -  person Iain Samuel McLean Elder    schedule 26.11.2013
comment
Я заменил ваши отформатированные данные операторами SQL, чтобы нам было легче ответить на ваш вопрос. Мы можем скопировать и вставить это в наши собственные редакторы запросов. Пожалуйста, исправьте любые неверные предположения, которые я сделал о вашей схеме.   -  person Iain Samuel McLean Elder    schedule 26.11.2013
comment
Запрос, который вы попробовали, не возвращает строк для вашего образца. Можете ли вы обновить образец данных с помощью лучшего примера?   -  person Iain Samuel McLean Elder    schedule 26.11.2013
comment
Спасибо, Иэн. Я не был знаком с этим термином. Однако да, вы правы; мой вопрос относится к тому же классу проблем.   -  person Glenn    schedule 26.11.2013


Ответы (2)


Попробуйте этот - я думаю, вы можете получить от него то, что хотите. Я использовал временную таблицу, которую вы могли бы избежать одним из нескольких способов, если хотите, но я думаю, что это облегчает визуализацию. Я также могу подумать о некоторых оптимизациях, но это будет хорошо работать для не слишком большого набора данных. Также могут быть некоторые граничные условия, о которых я не думаю. Хорошо, могу я уточнить свой ответ еще раз. . .

--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

Надеюсь это поможет

person EGP    schedule 26.11.2013
comment
Спасибо, ЕГП! Позвольте мне перевести это на MySQL, и я скоро вернусь, чтобы принять этот ответ. - person Glenn; 26.11.2013
comment
Это сработало прекрасно. Спасибо. Теперь, чтобы я провел следующий день, выясняя, как это работает. - person Glenn; 26.11.2013
comment
Рад, что это помогло. Я не уверен, есть ли точный термин для такого рода коррелированного подзапроса — я думаю о нем как об агрегированном коррелированном подзапросе. Я думаю, что есть лучший способ сделать это в предложении WHERE вместо SELECT, но мне это не пришло в голову. - person EGP; 26.11.2013