MySQL рассчитать расстояние для возвращения - PullRequest
0 голосов
/ 14 октября 2019

Это не дубликат: Найти расстояние между двумя точками, используя широту и долготу в mysql

Я пробовал запрос, и он не работает, я получаю пустой набор данныхи 0 в качестве ответа.

СМОТРИТЕ ответ, ЭТО решение, я не знаю, почему этот вопрос был помечен как дубликат из Shadow

У меня есть таблица со следующимструктура:

table: distance
id int(10) primary key
lat float,
lon float,
time timestamp

У меня есть приложение для Android, которое пингует мой сервер и добавляет запись каждый раз, когда он меняет положение.

например

id:1, lat:40.753979, lon:-111.881721, time = 1571004620
id:2, lat:40.753979, lon:-111.883721, time = 1571004630
id:3, lat:40.753979, lon:-111.885721, time = 1571004640

Я могу вычислитьобщее расстояние, если я иду в одном направлении:

/* in my python script*/
startLat,startLon = select lat,lon from distance where time >= 1571004620 order by time limit 1;
endLat,endLon = select lat,lon from distance where time <= 1571004640 order by time desc limit limit 1;

, тогда я могу вычесть обе координаты, что в итоге даст мне длинное расстояние 0,004000

, проблема:

, еслия добавляю:

id:4, lat:40.753979, lon:-111.881721, time = 1571004650

тогда я должен получить: 0,008000

но я получаю 0, поскольку позиция 1 совпадает с позицией 4

1 Ответ

2 голосов
/ 14 октября 2019

Вы можете воспользоваться пространственной поддержкой MySQL, доступной с 5.7, для выполнения всех вычислений в базе данных. Функция ST_Distance_Sphere() может использоваться для вычисления расстояний.

Вам действительно нужна совокупная сумма расстояния (для этого требуются оконные функции, доступные начиная с MySQL 8.0).

Рассмотрим:

SELECT
    id,
    time,
    SUM(
        CASE WHEN lag_lat IS NULL 
            THEN 0
            ELSE ST_Distance_Sphere(point(lag_lon, lag_lat), point(lon, lat))
        END
    ) OVER (ORDER BY time) cumulative_distance
FROM (
    SELECT
        d.*,
        LAG(lat) OVER(ORDER BY time) lag_lat,
        LAG(lon) OVER(ORDER BY time) lag_lon
    FROM distance d
)  x

Демонстрация по БД Fiddle :

| id  | time       | cumulative_distance |
| --- | ---------- | ------------------- |
| 1   | 1571004620 | 0                   |
| 2   | 1571004630 | 168.37177423236415  |
| 3   | 1571004640 | 336.7435484657999   |
| 4   | 1571004650 | 673.4870969097663   |

В более ранних версиях MySQL вам необходимо эмулироватьоконные функции:

  • LAG() можно заменить на self- LEFT JOIN с условием NOT EXISTS и коррелированным подзапросом в условии ON

  • переменные могут эмулировать накопительный SUM

Запрос:

SELECT
    id,
    time,
    @running_distance := @running_distance + CASE
        WHEN lag_lat IS NULL THEN 0
        ELSE ST_Distance_Sphere(point(lag_lon, lag_lat), point(lon, lat))
    END running_distance
FROM (
    SELECT
        d.id,
        d.time,
        d.lat,
        d.lon,
        d_lag.lat lag_lat,
        d_lag.lon lag_lon   
    FROM distance d
    LEFT JOIN distance d_lag
        ON  d_lag.time < d.time
        AND NOT EXISTS (
            SELECT 1 
            FROM distance d1
            WHERE d1.time < d.time AND d1.time > d_lag.time
        )
    ORDER BY d.time
) x
CROSS JOIN (SELECT @running_distance := 0) y

Демонстрация на DB Fiddle : те же результаты, что и выше.

...