Выбор первой и последней строки по группе в таблице MySQL с нюансом в группах - PullRequest
0 голосов
/ 14 июля 2020

Моя исследовательская группа каждую минуту собирает информацию о микромобильном велосипеде / самокате (при этом фактическая информация обновляется каждые 3-5 минут), которая предоставляет информацию о местонахождении велосипеда / скутера. Каждая недублирующаяся запись сохраняется в таблице freeBikeStatus:

CREATE TABLE `freeBikeStatus` (
  `bike_id` varchar(255) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `lon` double DEFAULT NULL,
  `lat` double DEFAULT NULL,
  `is_reserved` bigint(20) DEFAULT NULL,
  `is_disabled` bigint(20) DEFAULT NULL,
  `soc` double DEFAULT NULL,
  `provider` varchar(255) DEFAULT NULL,
  `system_name` varchar(255) NOT NULL,
  `timestamp` bigint(20) NOT NULL,
  `vehicle_type` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`bike_id`,`system_name`,`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Однако существует масса избыточной информации, потому что сам велосипед может не двигаться, но все равно будет записан в нескольких строках с разными отметки времени. Это может увеличить размер нашей базы данных в 40-50 раз, поэтому необходим запрос для уменьшения размера и устранения избыточной информации. В качестве примера:

==============================================
| row | bikeid | lat | lon | timestamp | ... |
==============================================
|  1  |   a    |  X  |  Y  |   1:01    | ... |
|  2  |   a    |  X  |  Y  |   1:03    | ... |
|  3  |   a    |  X  |  Y  |   1:05    | ... |
|  4  |   a    |  X  |  Y  |   1:08    | ... |
|  5  |   a    |  Z  |  Y  |   1:12    | ... |
|  6  |   a    |  Z  |  Y  |   1:15    | ... |
|  7  |   a    |  Z  |  Y  |   1:17    | ... |
|  8  |   a    |  Z  |  Y  |   1:19    | ... |
|  9  |   a    |  X  |  Y  |   1:22    | ... |
| 10  |   a    |  X  |  Y  |   1:25    | ... |
| 11  |   a    |  X  |  Y  |   1:27    | ... |
| 12  |   a    |  X  |  Y  |   1:29    | ... |

Поскольку велосипед фактически не перемещался с 1:01 на 1:08, с 1:12 на 1:19 и с 1:22 на 1:29, между рядами нет необходимости. Поэтому мы хотели бы заменить приведенную выше таблицу на таблицу ниже:

==============================================
| row | bikeid | lat | lon | timestamp | ... |
==============================================
|  1  |   a    |  X  |  Y  |   1:01    | ... |
|  4  |   a    |  X  |  Y  |   1:08    | ... |
|  5  |   a    |  Z  |  Y  |   1:12    | ... |
|  8  |   a    |  Z  |  Y  |   1:19    | ... |
|  9  |   a    |  X  |  Y  |   1:22    | ... |
| 12  |   a    |  X  |  Y  |   1:29    | ... |

Я придумал следующий запрос, основанный на аналогичном вопросе StackOverFlow ( Выбор первого и последнего значений в группе ).

WITH
  t1 AS (
    SELECT * AS lon, lat
    FROM freeBikeStatus
  ),
  t2 AS (
    SELECT t1.*,
    FIRST_VALUE(timestamp) OVER (PARTITION BY lat, lon ORDER BY timestamp) AS begin,
    LAST_VALUE(timestamp) OVER (PARTITION BY lat, lon ORDER BY timestamp) AS end
    FROM t1
  )
SELECT * FROM t2
GROUP BY lat, lon
ORDER BY lat, lon

Однако кажется, что в этом примере есть небольшая разница (что привело к запросу выше). Если велосипед возвращается к той же широте / долготе, я считаю, что запрос удалит все временные точки, даже если он переместится из точки A -> B -> A, что приведет к вырезанию одной конечной точки и одной начальной точки. Есть ли способ изменить этот запрос, чтобы учесть это?

1 Ответ

1 голос
/ 14 июля 2020

Используйте оконные функции LAG() и LEAD() для проверки предыдущего и следующего значений lat и lon каждой строки:

with cte as (
  select *,
    lag(lat) over (partition by bikeid order by timestamp) prev_lat,
    lead(lat) over (partition by bikeid order by timestamp) next_lat,
    lag(lon) over (partition by bikeid order by timestamp) prev_lon,
    lead(lon) over (partition by bikeid order by timestamp) next_lon
  from freeBikeStatus  
)
select `row`, bikeid, lat, lon, timestamp
from cte
where 
     (lat, lon) <> (prev_lat, prev_lon) 
  or (lat, lon) <> (next_lat, next_lon)
  or coalesce(prev_lat, prev_lon) is null
  or coalesce(next_lat, next_lon) is null
order by `row`

См. демонстрацию . Результатов:

| row | bikeid | lat | lon | timestamp |
| --- | ------ | --- | --- | --------- |
| 1   | a      | X   | Y   | 1:01      |
| 4   | a      | X   | Y   | 1:08      |
| 5   | a      | Z   | Y   | 1:12      |
| 8   | a      | Z   | Y   | 1:19      |
| 9   | a      | X   | Y   | 1:22      |
| 12  | a      | X   | Y   | 1:29      |
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...