MySQL为每行加入外表中的最新行

时间:2020-03-30 17:31:17

标签: mysql join

我有2个表,其中一个是位置(资产,时间戳和位置),另一个是状态更改(资产,时间戳和状态)。我正在尝试选择所有位置,并加入“当前状态”,该位置由位置时间戳(status.timestamp <= location.timestamp)之前的最新状态更改确定。

Locations
ID  Asset  Timestamp  Lat/Lon
1   A      1000       Lat/Lon
2   A      2000       Lat/Lon
3   A      3000       Lat/Lon

Status
ID  Asset  Timestamp  Status
1   A      1000       active
2   A      2200       sleep

我正在寻找的东西:

LocID  Asset  Timestamp  Lat/Lon  Status
1      A      1000       Lat/Lon  active
2      A      2000       Lat/Lon  active
3      A      3000       Lat/Lon  sleep

我知道“连接最近的一行”问题已被问过1000次,但是我对此问题的解决方案在这里不起作用。在这种情况下,我不仅要查找最新的行,还需要与位置表中的时间戳相对应的最新状态...而这超出了我的能力范围。

MariaDB 10.4.12

提前感谢您的帮助!

编辑:使用下面的row_number()的建议确实可以解决问题,但效率不高。在我的完整数据集上运行查询,它超时。有没有解决这个问题的方法?

1 个答案:

答案 0 :(得分:1)

在MySQL 8.x中,您可以使用ROW_NUMBER()窗口函数来过滤相关行。

例如:

select loc_id, asset, timestamp
from (
  select
    l.id as loc_id,
    l.asset,
    l.timestamp,
    row_number() over(partition by l.asset order by s.timestamp desc) as rn
  from locations l
  join status s on s.asset = l.asset and s.timestamp <= l.timestamp
) x
where rn = 1

whiteatom编辑: 为了将来的读者-这行得通。我只需要更改分区依据(重新启动编号;就像分组依据一样)。一旦将其更改为“按l.asset,l.timestamp分区”,它将在每个新位置的时间戳记重新开始编号,并且编号为1的行都是正确的。

工作示例:

select loc_id, lts, asset, location, status
from (
  select
    l.id as loc_id,
    l.asset,
    l.timestamp as lts,
    l.location,
    s.status,
    row_number() over(partition by l.asset, l.timestamp order by s.timestamp desc) as rn
  from location l
  join status s on s.asset = l.asset and s.timestamp <= l.timestamp
) x
where rn = 1
相关问题