选择mySQL中两个表最接近的时间戳?

时间:2018-02-16 21:12:39

标签: mysql sql

我有两张桌子。

表格提醒

username -- alert -- timestamp
abc -- 3 -- 2017-12-09 13:10:42
def -- 3 -- 2017-12-12 18:10:00
xyz -- 3 -- 2017-12-11 11:00:00

表格页

username -- url -- timestamp
abc -- home -- 2017-12-09 13:18:42
abc -- home -- 2017-12-13 19:03:10
def -- home -- 2017-12-13 13:33:00

我想要做的是展示usernamesalerts上找到的pages。但是,我只需要在pages上显示其时间戳最接近alerts时间戳的行。

这意味着

abc -- 3 -- 2017-12-09 13:10:42 -- home -- 2017-12-09 13:18:42
def -- 3 -- 2017-12-12 18:10:00 -- home -- 2017-12-13 13:33:00

到目前为止我做了什么

SELECT alerts.username, alerts.alert, alerts.timestamp, pages.url, pages.timestamp
FROM   alerts 
join pages on pages.username = alerts.username
WHERE  username IN(SELECT DISTINCT username
                               FROM   pages
                               WHERE  url = 'home' 
                                      AND timestamp > 
                                          alerts.timestamp) 
GROUP  BY username

但是这个查询不会返回最接近的,而是随机返回的(我猜最新的)。

我该如何解决这个问题?

3 个答案:

答案 0 :(得分:0)

SELECT DISTINCT a.username, abs(a.timestamp-p.timestamp) as difference  
FROM alerts a 
JOIN pages p ON p.username = a.username
HAVING difference = min(difference)

上面的查询将选择带有邮票之间绝对差异的用户名,然后它将仅返回差异最小的行。

SQL Fiddle

答案 1 :(得分:0)

您可能想尝试使用窗口函数:

select * from (
select 
  p.username,
  p.timestamp pages_timestamp,
  p.url,
  a.timestamp alerts_timestamp,
  a.alert,
  row_number() over (partition by p.username order by abs(p.timestamp - a.timestamp)) rn
from alerts a
join pages p on a.username = p.username) t
where t.rn = 1

我们正在加入用户名表来计算每个匹配对的时差。我们为分区中的每一行分配一个row_number,该行共享相同的用户名(按时差排序),只选择行号为1的行(即时差最小的行)

如果每个表中每个用户有足够的行,您可能需要在select表中添加where abs(p.timestamp - a.timestamp) < SOME_LIMIT

更新:如果您运行MySQL 5.6或类似版本,那么您对窗口函数运气不佳,您将不得不应用旧的逐个连接技巧:< / p>

select 
  p.username,
  p.url,
  p.timestamp pages_timestamp,
  a.alert,
  a.timestamp alerts_timestamp
from (
  select 
    p.username,
    min(abs(p.timestamp - a.timestamp)) min_diff
  from alerts a
  join pages p on a.username = p.username
  group by p.username) t
join pages p on p.username = t.username
join alerts a on a.username = p.username
where abs(p.timestamp - a.timestamp) = t.min_diff

请注意,如果(且仅当)pages中有多个行与同一username的警报中的某些行具有相同的时间差,则会为每个用户生成重复的行。

DB Fiddle(使用MySQL 5.6) DB Fiddle(使用MySQL 8)

答案 2 :(得分:0)

这是另一个想法 - 创建一个临时表,两个时间戳(每个用户)之间的时间差最小 - 然后链接到临时表和WHERE子句通过匹配值获得最接近的时间戳计算。

代码示例:

    SELECT A.UserName, MIN(CONVERT(DECIMAL(6,2),P.TimeStamp -A.timestamp)) TimeDif
    INTO #Temp1
    FROM Alerts A INNER JOIN Pages P ON A.UserName = P.username
    GROUP BY A.UserName

    SELECT A.UserName, A.Alert, P.url, P.timestamp
    FROM Alerts A INNER JOIN
       Pages P ON A.UserName = P.username INNER JOIN
       #Temp1 T ON A.UserName = T.UserName
    WHERE T.TimeDif = CONVERT(DECIMAL(6,2),P.TimeStamp -A.timestamp)