我正在为基于位置的签到构建一个 Web 应用程序,有点像本地 4square,但基于 RFID 标签。
无论如何,每次签入都存储在一个 MySQL 表中,其中包含一个用户 ID 和签入时间作为 DATETIME 列。
现在我想显示哪些用户在不同车站之间的签到时间最近。
解释:假设用户 A 在 21:43:12 签到,然后在 21:43:19 签到。他在 7 秒内移动了两个站点。
数据库中有数千个签到,我如何编写 SQL 来选择两个签到时间最接近的用户?
真正快速的解决方案会引入一些预先计算。就像存储当前和以前签入之间的差异一样。
在这种情况下,您可以快速选择所需的内容(只要您按索引覆盖该列)。
在这种情况下不使用预计算会导致可怕的查询,这些查询将在类似笛卡尔的产品上运行。
尝试这个:
select
a.id,
b.id,
abs(a.rfid-b.rfid)
from
table1 a,
table1 a
where
a.userID=b.userID
// and any other conditions to make it a single user
group by
a.id,
b.id,
a.rfid,
b.rfid
order by
abs(a.rfid-b.rfid) desc
limit 1
我想,您只想计算两次签到之间的差异,如果它们是同一个人的两次连续签到。
create table test (
id int,
person_id int,
checkin datetime);
insert into test (id, person_id, checkin) values (1, 1, now());
insert into test (id, person_id, checkin) values (2, 1, now());
insert into test (id, person_id, checkin) values (3, 2, now());
insert into test (id, person_id, checkin) values (4, 2, now());
insert into test (id, person_id, checkin) values (5, 1, now());
insert into test (id, person_id, checkin) values (6, 2, now());
insert into test (id, person_id, checkin) values (7, 1, now());
select * from (
select a.*,
(select a.checkin - b.checkin
from test b where b.person_id = a.person_id
and b.checkin < a.checkin
order by b.checkin desc
limit 1
) diff
from test a
where a.person_id = 1
order by a.person_id, a.checkin
) tt
where diff is not null
order by diff asc;
你试过什么?你看过 DATEDIFF http://msdn.microsoft.com/en-us/library/ms189794.aspx
干杯——乔克
首先,您需要用户的索引,然后是时间戳。
其次,您需要使用相关的子查询来查找“下一个时间戳”。
然后使用 GROUP BY 来查找每个用户的最小间隔。
SELECT
a.user_id,
MIN(TIMEDIFF(b.timestamp, a.timestamp)) AS min_duration,
FROM
checkin AS a
INNER JOIN
checkin AS b
ON b.user_id = a.user_id
AND b.timestamp = (SELECT MIN(timestamp)
FROM checkin
WHERE user_id = a.user_id
AND timestamp > a.timestamp)
GROUP BY
a.user_id
ORDER BY
min_duration
LIMIT
1
如果您想允许多个用户使用相同的min_duration
,我建议将结果(不带LIMIT 1
)存储在临时表中,然后在该表中搜索共享最短持续时间的所有用户。
根据数据量,这可能会很慢。一种优化是缓存TIMEDIFF()
. 每次记录新签入时,还要计算并存储自上次签入以来的持续时间,可能使用触发器。预先计算此值可使查询更简单且值可索引。
SELECT a.*, b.*
FROM table_name AS a
JOIN table_name AS b
ON a.id != b.id
ORDER BY TIMESTAMPDIFF(SECOND, a.checkin, b.checkin) ASC
LIMIT 1
应该这样做。如前所述,可能有点滞后。