Если я правильно понял ваш вариант использования, я считаю, что вам не нужно создавать LineStrings, чтобы проверить, пересекается ли ваша траектория или приближается в определенный момент времени.
Образец данных:
CREATE TABLE t (vehicle_id INT, longitude NUMERIC, latitude NUMERIC, ts TIMESTAMP);
INSERT INTO t VALUES (1,1,1.1111,'2019-05-01 15:30:00'),
(1,1,2.1112,'2019-05-01 15:40:00'),
(1,1,3.1111,'2019-05-01 15:50:00'),
(2,2,2.1111,'2019-05-01 15:30:00'),
(2,1,2.1111,'2019-05-01 15:40:00'),
(2,1,4.1111,'2019-05-01 15:05:00');
Как видно из приведенных выше примеров данных, vehicle_id
1 и 2 расположены близко (менее 30 м) друг к другу на 2019-05-01 15:40:00
, что можно найти с помощью запроса, подобного следующему:
SELECT
t1.vehicle_id,t2.vehicle_id,t1.ts,
ST_AsText(ST_MakePoint(t1.longitude,t1.latitude)::GEOGRAPHY) AS p1,
ST_AsText(ST_MakePoint(t2.longitude,t2.latitude)::GEOGRAPHY) AS p2,
ST_Distance(
ST_MakePoint(t1.longitude,t1.latitude)::GEOGRAPHY,
ST_MakePoint(t2.longitude,t2.latitude)::GEOGRAPHY) AS distance
FROM t t1, t t2
WHERE
t1.vehicle_id <> t2.vehicle_id AND
t1.ts = t2.ts AND
ST_Distance(
ST_MakePoint(t1.longitude,t1.latitude)::GEOGRAPHY,
ST_MakePoint(t2.longitude,t2.latitude)::GEOGRAPHY) <= 30
vehicle_id | vehicle_id | ts | p1 | p2 | distance
------------+------------+---------------------+-----------------+-----------------+-------------
1 | 2 | 2019-05-01 15:40:00 | POINT(1 2.1112) | POINT(1 2.1111) | 11.05757826
2 | 1 | 2019-05-01 15:40:00 | POINT(1 2.1111) | POINT(1 2.1112) | 11.05757826
(2 rows)
Как видите, результат в некотором роде дублируется, поскольку 1 близко к 2, а 2 близко к 1 одновременно. Вы можете исправить это, используя DISTINCT ON()
, но, поскольку я не знаком с вашими данными, думаю, вам лучше настроить это самостоятельно.
Обратите внимание, что тип данных GEOGRAPHY
, а не GEOMETRY
. Это потому, что расстояния с ST_Distance
по геометриям рассчитываются в градусах, а с использованием географии - в метрах.
РЕДАКТИРОВАТЬ: Чтобы ответить на вопрос, упомянутый в комментариях.
Чтобы избежать ненужных затрат при создании записей географии во время выполнения, вы можете захотеть уже сохранить координатыкак география. В этом случае таблица будет выглядеть следующим образом ..
CREATE TABLE t (vehicle_id INT, geom GEOGRAPHY, ts TIMESTAMP);
И вы можете заполнить ее следующим образом.
INSERT INTO t (vehicle_id, geom, ts)
VALUES (1,ST_MakePoint(1,1.1111),'2019-05-01 15:30:00');
В случае, если вы хотите избежать повторного заполнения таблицы,Вы можете просто переместить данные в другой столбец и избавиться (если хотите) от широты и долготы:
ALTER TABLE t ADD COLUMN geom GEOGRAPHY;
UPDATE t SET geom = ST_MakePoint(longitude,latitude);
ALTER TABLE t DROP COLUMN longitude, DROP COLUMN latitude;
CREATE INDEX idx_point ON t USING GIST(geom);
SELECT vehicle_id,ts,ST_AsText(geom) FROM t;
vehicle_id | ts | st_astext
------------+---------------------+-----------------
1 | 2019-05-01 15:30:00 | POINT(1 1.1111)
1 | 2019-05-01 15:40:00 | POINT(1 2.1112)
1 | 2019-05-01 15:50:00 | POINT(1 3.1111)
2 | 2019-05-01 15:30:00 | POINT(2 2.1111)
2 | 2019-05-01 15:40:00 | POINT(1 2.1111)
2 | 2019-05-01 15:05:00 | POINT(1 4.1111)
(6 rows)