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

Laravel里程追踪器开发求助:基于上条里程数据计算行驶公里数

解决方案

一、MySQL 实现方案

1. MySQL 8.0+(推荐,支持窗口函数)

直接用LAG()窗口函数获取上一行的odometer_stop值,计算行驶里程:

SELECT 
    id,
    -- 首行用手动输入的odometer_start,后续行用上一行的odometer_stop
    IFNULL(LAG(odometer_stop) OVER (ORDER BY created_at ASC), odometer_start) AS odometer_start,
    odometer_stop,
    fuel,
    -- 计算行驶里程
    odometer_stop - IFNULL(LAG(odometer_stop) OVER (ORDER BY created_at ASC), odometer_start) AS km_travelled,
    created_at
FROM mileage_records;

如果是多车辆分开计算,加上PARTITION BY分组即可:

LAG(odometer_stop) OVER (PARTITION BY vehicle_id ORDER BY created_at ASC)

2. MySQL 5.x 兼容方案(无窗口函数)

用用户变量存储上一行的里程值:

SELECT 
    id,
    @prev_stop AS odometer_start,
    odometer_stop,
    fuel,
    odometer_stop - @prev_stop AS km_travelled,
    -- 更新变量为当前行的结束里程,供下一行使用
    @prev_stop := odometer_stop
FROM mileage_records,
(SELECT @prev_stop := (SELECT odometer_start FROM mileage_records ORDER BY created_at ASC LIMIT 1)) AS init
ORDER BY created_at ASC;

二、Laravel 实现方案

1. 新增记录时自动填充odometer_start

在模型的creating事件中自动获取上一条记录的结束里程作为当前记录的起始里程,不需要用户手动输入(首条记录除外):
首先在MileageRecord模型中添加如下代码:

protected static function booted()
{
    static::creating(function ($record) {
        // 如果是多车辆,追加 ->where('vehicle_id', $record->vehicle_id) 条件
        $lastRecord = static::latest('created_at')->first();
        if ($lastRecord) {
            $record->odometer_start = $lastRecord->odometer_stop;
        }
        // 自动计算行驶里程
        $record->km_travelled = $record->odometer_stop - $record->odometer_start;
    });
}

新增记录时只需要传入odometer_stop和fuel即可,首条记录需要额外传入手动填写的odometer_start。

2. 查询时动态计算行驶里程

如果不想在数据库存储km_travelled字段,查询时动态计算:

// MySQL 8.0+ 版本
$records = MileageRecord::select([
    '*',
    DB::raw('IFNULL(LAG(odometer_stop) OVER (ORDER BY created_at ASC), odometer_start) as calculated_odometer_start'),
    DB::raw('odometer_stop - IFNULL(LAG(odometer_stop) OVER (ORDER BY created_at ASC), odometer_start) as km_travelled'),
])->get();

如果数据量较小,也可以用Laravel集合处理,兼容所有数据库版本:

$records = MileageRecord::oldest('created_at')->get();
$prevStop = $records[0]->odometer_start;
$records->transform(function ($item) use (&$prevStop) {
    $item->km_travelled = $item->odometer_stop - $prevStop;
    $prevStop = $item->odometer_stop;
    return $item;
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 14:54:01