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

按组检测累计里程:用SQL替代Excel宏实现1小时超20英里检测

用SQL检测卡车1小时内行驶里程超20英里的时间点

需求说明

需要从卡车行驶里程记录表中,识别出每辆卡车首次在1小时窗口内累计行驶里程超过20英里的时间点,输出对应时间、卡车编号及累计里程。现有Excel逐行扫描宏处理数千行数据时效率低下,改用SQL提升处理速度。

示例输入数据

Date                Truck   Dist
05/11/2023 03:12:40 A       9.6
05/11/2023 03:43:25 A       6.5
05/11/2023 04:14:24 A       5.6
05/11/2023 04:43:55 A       7.4
05/11/2023 05:14:10 A       8.7
05/11/2023 05:24:39 A       8.9
05/11/2023 06:41:40 A       12.1
05/11/2023 04:13:33 B       11.5
05/11/2023 04:53:49 B       16.6
05/11/2023 06:14:04 B       7.4
05/11/2023 06:34:19 B       9.2
05/11/2023 07:04:34 B       9.5
05/11/2023 08:24:49 B       0.8

期望输出结果

Date                Truck   Dist
05/11/2023 04:14:24 A       21.7
05/11/2023 05:24:39 A       25
05/11/2023 04:53:49 B       28.1
05/11/2023 07:04:34 B       26.1

现有Excel VBA宏代码

For i = 2 To lastrow
        t = i
        cont = Sheets("Data").Range("C" & i)
        Do While Sheets("Data").Range("B" & i) = Sheets("Data").Range("B" & i + 1) And DateDiff("s", Sheets("Data").Range("A" & i).Value, Sheets("Data").Range("A" & t).Value) <= 3600
            cont = cont + Sheets("Data").Range("C" & t)
            t = t + 1
            If cont >= 20 Then
            Sheets("Data").Range("D" & t) = cont
            i = t
            Exit Do
            End If
        Loop
Next

SQL解决方案

通用版(适用于所有支持SQL的数据库)

通过自连接计算1小时窗口内的累计里程,并筛选首次达标记录:

WITH truck_sorted AS (
    -- 按卡车分组、时间排序,添加行号
    SELECT 
        Date,
        Truck,
        Dist,
        ROW_NUMBER() OVER (PARTITION BY Truck ORDER BY Date) AS rn
    FROM your_table_name
),
window_totals AS (
    -- 计算每个时间点对应的1小时窗口内的累计里程
    SELECT
        t1.Date,
        t1.Truck,
        SUM(t2.Dist) AS total_dist,
        t1.rn
    FROM truck_sorted t1
    JOIN truck_sorted t2
        ON t1.Truck = t2.Truck
        -- 确保t2的时间在t1的前1小时内
        AND t2.Date >= DATEADD(HOUR, -1, t1.Date)
        AND t2.Date <= t1.Date
    GROUP BY t1.Date, t1.Truck, t1.rn
),
trigger_candidates AS (
    SELECT
        Date,
        Truck,
        total_dist,
        -- 标记是否为首次达标:当前累计≥20,且窗口内前一个记录的累计<20
        CASE
            WHEN total_dist >= 20
                 AND COALESCE(
                     (SELECT total_dist FROM window_totals wt 
                      WHERE wt.Truck = window_totals.Truck 
                        AND wt.rn = window_totals.rn - 1
                        AND wt.Date >= DATEADD(HOUR, -1, window_totals.Date)),
                     0
                 ) < 20
            THEN 1
            ELSE 0
        END AS is_first_trigger
    FROM window_totals
)
-- 输出最终结果
SELECT
    Date,
    Truck,
    total_dist AS Dist
FROM trigger_candidates
WHERE is_first_trigger = 1;

优化版(适用于支持时间范围窗口函数的数据库:SQL Server、PostgreSQL等)

利用窗口函数直接计算滚动累计,代码更简洁高效:

WITH rolling_totals AS (
    SELECT
        Date,
        Truck,
        SUM(Dist) OVER (
            PARTITION BY Truck
            ORDER BY Date
            RANGE BETWEEN INTERVAL 1 HOUR PRECEDING AND CURRENT ROW
        ) AS total_dist
    FROM your_table_name
),
valid_triggers AS (
    SELECT
        Date,
        Truck,
        total_dist,
        -- 筛选首次达标的记录
        LAG(total_dist, 1, 0) OVER (PARTITION BY Truck ORDER BY Date) AS prev_total
    FROM rolling_totals
)
SELECT
    Date,
    Truck,
    total_dist AS Dist
FROM valid_triggers
WHERE total_dist >= 20 AND prev_total < 20;

针对MySQL的适配版

MySQL不支持RANGE BETWEEN INTERVAL,可改用自连接方式:

WITH truck_sorted AS (
    SELECT 
        Date,
        Truck,
        Dist,
        ROW_NUMBER() OVER (PARTITION BY Truck ORDER BY Date) AS rn
    FROM your_table_name
),
window_totals AS (
    SELECT
        t1.Date,
        t1.Truck,
        SUM(t2.Dist) AS total_dist,
        t1.rn
    FROM truck_sorted t1
    JOIN truck_sorted t2
        ON t1.Truck = t2.Truck
        AND t2.Date >= DATE_SUB(t1.Date, INTERVAL 1 HOUR)
        AND t2.Date <= t1.Date
    GROUP BY t1.Date, t1.Truck, t1.rn
),
trigger_candidates AS (
    SELECT
        Date,
        Truck,
        total_dist,
        CASE
            WHEN total_dist >= 20
                 AND COALESCE(
                     (SELECT total_dist FROM window_totals wt 
                      WHERE wt.Truck = window_totals.Truck 
                        AND wt.rn = window_totals.rn - 1
                        AND wt.Date >= DATE_SUB(window_totals.Date, INTERVAL 1 HOUR)),
                     0
                 ) < 20
            THEN 1
            ELSE 0
        END AS is_first_trigger
    FROM window_totals
)
SELECT
    Date,
    Truck,
    total_dist AS Dist
FROM trigger_candidates
WHERE is_first_trigger = 1;

逻辑说明

  1. 排序分组:先按卡车分组、时间排序,为每条记录添加行号,方便后续关联计算。
  2. 窗口累计:通过自连接或窗口函数,计算每个时间点往前1小时内的累计行驶里程。
  3. 筛选触发点:识别出累计里程首次超过20英里的时间点,避免重复输出同一连续窗口内的多条达标记录。

内容的提问来源于stack exchange,提问作者David Ricardo Menacho Vadillo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:07:32