SQL 查询仅获取事件的开始和结束时间

标签 sql gaps-and-islands

我有两个表:

  • 位置 - 存储用户的地理位置和时间戳。
  • 事件 - 存储事件的地理范围以及摇滚音乐会事件的开始和结束时间。

是否有查询可以获取所有用户参加事件的开始和结束时间?

以下是数据示例:

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 风格的答案。)

最佳答案

试试这个 - 我想你可以从中得到你想要的。我使用了临时表,如果您愿意,您可以通过多种方式之一来避免它,但我认为它更容易可视化。我也可以想到一些优化,但这对于不太庞大的数据集来说效果很好。可能还有一些我没有想到的边界条件。好吧,我可以再限定一下我的答案吗? 。 .

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

希望这有帮助

关于SQL 查询仅获取事件的开始和结束时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20207317/

相关文章:

sql - 枚举 Postgres 表中的表分区

sql - 连续日期postgresql

sql - 根据时间合并两个表

用于发送电子邮件的 SQL Server 存储过程

mysql - 从同一个表计算回合(平均值)并连接

php - 按 desc 排序似乎失败

sql - 如何使用 SQL 计算列中非连续值的数量?

php - 如何在 SQL 中对多个字段进行排序和过滤搜索

sql - 以编程方式构建 SQL 查询的可靠方法

sql - 行集中、周期日期