You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何计算同用户相邻行的地理距离?SQL实现求助

需求:计算同user_id下每行到下一行的地理距离

原始表结构及数据

idperioduser_idactionlatitudelongitude
12022-10-14 02:29:26110run background-6.280288219451904106.82013702392578
22022-10-14 03:29:26120run background-6.281721591949463106.82991790771484
32022-10-14 04:29:26110run background-6.280627250671387106.82881927490234
42022-10-14 05:29:26120run background-6.280624866485596106.82881927490234

预期结果表

idperioduser_idactionlatitudelongitudeto_latitudeto_longitudedistance_meters
12022-10-14 02:29:26110run background-6.280106.820-6.288106.82850
32022-10-14 04:29:26110run background-6.288106.828
22022-10-14 03:29:26120run background-6.281106.829-6.283106.82955
42022-10-14 05:29:26120run background-6.283106.829

已尝试的SQL语句

SELECT 
      datetime(t1.created_at) period
     , t1.user_id
     , t1.action
     , t1.Latitude AS LatFrom
     , t1.Longitude AS LongFrom
     , t2.Latitude AS LatTo
     , t2.Longitude AS LongTo
FROM geolocation t1
LEFT OUTER JOIN geolocation t2 ON t2.promotor_id=t1.promotor_id AND t2.id > t1.id
WHERE 
group by 1,2,3,4,5,6,7
Order by 1

优化方案及SQL

原SQL存在两个核心问题:

  1. 关联字段错误:误用promotor_id而非需求中的user_id;
  2. 关联逻辑错误:t2.id > t1.id会关联当前行之后的所有行,无法精准获取下一行数据。

正确做法是用窗口函数LEAD(),按user_id分组、period排序,直接获取同用户下一行的经纬度,再通过Haversine公式计算地理距离(单位:米):

SELECT
    id,
    period,
    user_id,
    action,
    ROUND(latitude, 3) AS latitude,
    ROUND(longitude, 3) AS longitude,
    ROUND(LEAD(latitude) OVER (PARTITION BY user_id ORDER BY period), 3) AS to_latitude,
    ROUND(LEAD(longitude) OVER (PARTITION BY user_id ORDER BY period), 3) AS to_longitude,
    -- Haversine公式计算两点间地表距离(单位:米)
    CASE
        WHEN LEAD(latitude) OVER (PARTITION BY user_id ORDER BY period) IS NOT NULL
        THEN ROUND(
            6371000 * 2 * ASIN(
                SQRT(
                    POW(SIN((LEAD(latitude) OVER (PARTITION BY user_id ORDER BY period) - latitude) * PI()/180 / 2), 2) +
                    COS(latitude * PI()/180) * COS(LEAD(latitude) OVER (PARTITION BY user_id ORDER BY period) * PI()/180) *
                    POW(SIN((LEAD(longitude) OVER (PARTITION BY user_id ORDER BY period) - longitude) * PI()/180 / 2), 2)
                )
            )
        , 0)
        ELSE NULL
    END AS distance_meters
FROM geolocation
ORDER BY user_id, period;

说明

  • LEAD() OVER (PARTITION BY user_id ORDER BY period):按用户分组、时间排序,精准获取当前行的下一行经纬度数据;
  • Haversine公式:基于球面几何计算两点间的地表距离,结果单位为米;
  • ROUND()函数:匹配预期结果的小数位数,距离取整显示。

内容的提问来源于stack exchange,提问作者D_Q

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 10:35:29