0

我有一个 MySQL 数据库表,其中包含纬度、经度、日期、时间、engine_state列。

我想计算车辆在两个日期之间行驶的距离。我找到了一个线程,它解释了如何进行查询和计算,但我的情况有点复杂,因为我必须根据引擎的状态进行计算。

最简单的方法是查询所有数据并使用 java 进行,但获取所有数据大约需要 20 秒,这对于我的需要来说非常缓慢。

困难的方法是查询数据库并告诉它为我计算它并只给我结果。

所以这是我拥有的数据的一个例子:

          Latitude    Longtitude   Date      Time    Engine 
   row 1: 23.3232     42.43344     130510    120030  1
   row 2: 23.3233     42.43354     130510    120031  1
   row 3: 23.3243     42.43321     130510    120032  1
   row 4: 23.3243     42.43321     130510    120033  0
   row 5: 23.3243     42.43321     130510    120034  0
   row 6: 23.3243     42.43321     130510    120035  1
   row 7: 23.3254     42.43332     130510    120036  1

   and so on....

“引擎”列可能是1 - 引擎正在工作0 - 引擎不工作

所以我想计算两个日期之间的距离,不包括引擎状态 = 0 的坐标。所以在这种情况下,我需要将第 1 行和第 4 行之间的距离与第 5 行和第 7 行之间的距离相加。

还要记住,查询首先需要告诉数据库按日期、时间排序,因为有时表数据没有排序。

任何人都知道如何使用 MySQL 进行这样的查询?

PS计算我想使用的距离的公式是Haversine(不是Vincety)

4

2 回答 2

1

假设您有一个计算Haversine距离的函数,您可以执行以下操作:-

SELECT SUM(func_Haversine(Loc1.Latitude, Loc1.Longtitude, Loc2.Latitude, Loc2.Longtitude))
FROM
(
    SELECT Latitude, Longtitude, @Cnt1:=@Cnt1+1 AS SeqCnt
    FROM 
    (
        SELECT Latitude, Longtitude
        FROM SomeTable
        WHERE `Date` BETWEEN '13-05-10' AND '13-05-10'
        AND Engine = 1
        ORDER BY `Date`, `Time`
    ) Sub0
    CROSS JOIN (SELECT @Cnt1:=0) Sub1
) Loc1
INNER JOIN
(
    SELECT Latitude, Longtitude, @Cnt2:=@Cnt2+1 AS SeqCnt
    FROM 
    (
        SELECT Latitude, Longtitude
        FROM SomeTable
        WHERE `Date` BETWEEN '13-05-10' AND '13-05-10'
        AND Engine = 1
        ORDER BY `Date`, `Time`
    ) Sub0
    CROSS JOIN (SELECT @Cnt2:=1) Sub1
) Loc2
ON Loc1.SeqCnt = Loc2.SeqCnt

这是获取所有相关记录,添加序列号并获取每条记录及其后续记录。然后得到每个点之间的距离,然后将距离相加

您可以直接在查询中使用 Haversine 公式,但如果只是给出基本 SQL 的概念,阅读起来会相当混乱且不必要

您已经包含了一个日期列和一个时间列,但是根据您的描述,我假设它只是您感兴趣的日期范围,并且时间仅用于对记录进行排序

我已经敲定了查询的基础知识和 SQLfiddle(带回行但不计算半正弦距离)。

http://sqlfiddle.com/#!2/1f014a/10

于 2013-10-10T15:37:39.910 回答
0

我会把它留在这里以防有人需要它。这是对 Laravel 的 @Kickstart 解释。

$sub = DB::query()->selectRaw(implode(', ', [
    'Loc1.latitude as latitude_from',
    'Loc1.longitude as longitude_from',
    'Loc2.latitude as latitude_to',
    'Loc2.longitude as longitude_to',
    'ST_Distance_Sphere(point(Loc1.longitude, Loc1.latitude),point(Loc2.longitude, Loc2.latitude)) as dist',
]))->fromSub(function ($query) {

    $query->selectRaw(implode(', ', [
        'latitude',
        'longitude',
        '@Cnt1 := @Cnt1+1 AS SeqCnt',
    ]))->fromSub(function ($query) {

        $query->select([
            'latitude',
            'longitude',
        ])->from('tracker_coords')
            ->where('tracker_id', 155)
            ->whereBetween('created_at', [
                '2020-10-02T13:00:00.000000Z',
                '2020-10-03T07:45:00.000000Z'
            ])
            ->orderBY('created_at');

    }, 'Sub0')->crossJoin(
        DB::raw('(SELECT @Cnt1:=0) as Sub1')
    );
}, 'Loc1')->joinSub(function($query) {

    $query->selectRaw(implode(', ', [
        'latitude',
        'longitude',
        '@Cnt2 := @Cnt2+1 AS SeqCnt',
    ]))->fromSub(function ($query) {

        $query->select([
            'latitude',
            'longitude',
        ])->from('tracker_coords')
            ->where('tracker_id', 155)
            ->whereBetween('created_at', [
                '2020-10-02T13:00:00.000000Z',
                '2020-10-03T07:45:00.000000Z'
            ])
            ->orderBY('created_at');

    }, 'Sub0')->crossJoin(
        DB::raw('(SELECT @Cnt2:=1) Sub1')
    );

}, 'Loc2', 'Loc1.SeqCnt', '=', 'Loc2.SeqCnt')->get();

简单用法:

$coords = $this->getConcatQueryString([
    't1.latitude as latitude_from',
    't1.longitude as longitude_from',
    't2.latitude as latitude_to',
    't2.longitude as longitude_to',
   'ST_Distance_Sphere(point(t1.longitude,t1.latitude),point(t2.longitude, t2.latitude)) as dist',
], fn($query) => $query
    ->from('tracker_coords')
    ->select([
        'latitude',
        'longitude',
        'created_at',
    ])
    ->where('tracker_id', $tracker->id)
    ->whereBetween('created_at', [
        $item->event_at,
        $item->event_to,
    ])
    ->orderBy('created_at')
)->get()->sum('dist');


private function getConcatQuery(array $select, $f)
{
    return DB::query()->selectRaw(implode(', ', $select))
        ->fromSub(function ($query) use ($f) {
            $query->selectRaw(implode(', ', [
                '*',
                '@Cnt1 := @Cnt1+1 AS SeqCnt',
            ]))->fromSub($f, 'Sub0')->crossJoin(
                DB::raw('(SELECT @Cnt1:=0) as Sub1')
            );
        }, 't1')->joinSub(function($query) use ($f) {
            $query->selectRaw(implode(', ', [
                '*',
                '@Cnt2 := @Cnt2+1 AS SeqCnt',
            ]))->fromSub($f, 'Sub0')->crossJoin(
                DB::raw('(SELECT @Cnt2:=1) Sub1')
            );
        }, 't2', 't1.SeqCnt', '=', 't2.SeqCnt');
}
于 2020-10-07T21:29:15.477 回答