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

基于Haversine公式获取最近匹配并实现SQL Update的技术问询

解决方案:直接用SQL筛选最近匹配并更新失败配送的RouteID

我明白你的痛点:原SQL会生成所有失败配送(ROUTEID LIKE '%NDD%')和有效新配送的组合,数据量爆炸,还要手动去重。咱们可以用窗口函数直接锁定每个失败配送的最近匹配,然后一步完成更新。

第一步:先验证最近匹配的结果

先写个查询确认每个失败配送对应的最近有效站点,这样你可以先核对数据是否正确:

WITH ValidDeliveryStops AS (
    -- 先把所有符合要求的新配送站点单独拎出来
    SELECT 
        lat AS latpoint,
        lon AS longpoint,
        RouteID,
        Sequence
    FROM tblOrderRouteStops WITH (NOLOCK)
    WHERE 
        CustID = 180016
        AND RouteID NOT LIKE '%NDD%'
        AND RouteID NOT LIKE '%PND%'
        AND RouteID NOT LIKE '%NFW%'
),
DistanceCalculations AS (
    -- 计算每个失败配送和所有有效站点的距离,同时给每个失败配送的匹配项按距离排名
    SELECT 
        ORS.PKID AS FailedStopID,
        ORS.Reference1,
        VDS.RouteID AS TargetRouteID,
        ROUND(
            ACOS(
                COS(RADIANS(90 - ORS.lat)) * COS(RADIANS(90 - VDS.latpoint)) +
                SIN(RADIANS(90 - ORS.lat)) * SIN(RADIANS(90 - VDS.latpoint)) * COS(RADIANS(ORS.lon - VDS.longpoint))
            ) * 3958.756,
            2
        ) AS Distance_in_mi,
        -- 关键:按失败配送分组,距离最近的排第1
        ROW_NUMBER() OVER (
            PARTITION BY ORS.PKID 
            ORDER BY ACOS(
                COS(RADIANS(90 - ORS.lat)) * COS(RADIANS(90 - VDS.latpoint)) +
                SIN(RADIANS(90 - ORS.lat)) * SIN(RADIANS(90 - VDS.latpoint)) * COS(RADIANS(ORS.lon - VDS.longpoint))
            ) ASC
        ) AS RankByDistance
    FROM tblOrderRouteStops ORS WITH (NOLOCK)
    CROSS JOIN ValidDeliveryStops VDS
    WHERE 
        ORS.CustID = 180016
        AND ORS.RouteID LIKE '%NDD%'
)
-- 只取每个失败配送排名第1的(最近的)匹配
SELECT 
    FailedStopID,
    Reference1,
    TargetRouteID,
    Distance_in_mi
FROM DistanceCalculations
WHERE RankByDistance = 1
ORDER BY FailedStopID;

第二步:转换成UPDATE语句更新RouteID

确认上面的查询结果没问题后,就可以把这个逻辑改成UPDATE,直接把失败配送的RouteID替换成最近匹配的有效RouteID:

WITH ValidDeliveryStops AS (
    SELECT 
        lat AS latpoint,
        lon AS longpoint,
        RouteID
    FROM tblOrderRouteStops WITH (NOLOCK)
    WHERE 
        CustID = 180016
        AND RouteID NOT LIKE '%NDD%'
        AND RouteID NOT LIKE '%PND%'
        AND RouteID NOT LIKE '%NFW%'
),
NearestMatches AS (
    SELECT 
        ORS.PKID AS FailedStopID,
        VDS.RouteID AS TargetRouteID,
        ROW_NUMBER() OVER (
            PARTITION BY ORS.PKID 
            ORDER BY ACOS(
                COS(RADIANS(90 - ORS.lat)) * COS(RADIANS(90 - VDS.latpoint)) +
                SIN(RADIANS(90 - ORS.lat)) * SIN(RADIANS(90 - VDS.latpoint)) * COS(RADIANS(ORS.lon - VDS.longpoint))
            ) ASC
        ) AS RankByDistance
    FROM tblOrderRouteStops ORS WITH (NOLOCK)
    CROSS JOIN ValidDeliveryStops VDS
    WHERE 
        ORS.CustID = 180016
        AND ORS.RouteID LIKE '%NDD%'
)
UPDATE ORS
SET ORS.RouteID = NM.TargetRouteID
FROM tblOrderRouteStops ORS
INNER JOIN NearestMatches NM 
    ON ORS.PKID = NM.FailedStopID
WHERE 
    NM.RankByDistance = 1
    AND ORS.CustID = 180016
    AND ORS.RouteID LIKE '%NDD%';

几个重要的注意点

  • 关于重复距离:如果有多个有效站点和某个失败配送的距离完全一样,ROW_NUMBER()会随机选一个。如果需要保留所有并列最近的,或者有其他规则,可以改成RANK();
  • 先查后更:一定要先运行第一步的查询确认匹配结果正确,再执行UPDATE,避免误改数据;
  • NOLOCK提示:保留了你原SQL里的WITH (NOLOCK),但要注意这个提示可能会读取未提交的脏数据,如果业务对数据一致性要求高,可以去掉;
  • 性能优化:如果数据量很大(比如你说的5000个站点),可以考虑给CustID、RouteID、lat、lon这些字段加索引,提升计算速度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:46:39