У меня есть большой набор данных (~ 2 млн строк), который описывает данные об автомобилях, когда они перемещаются по большому парковочному комплексу. То есть каждое транспортное средство сканируется, когда оно проходит через несколько «зон» в конструкции. Это выглядит примерно так:
+--------+----------------+----------+---------------------+
| id | zone_camera_id | plate | timestamp |
+--------+----------------+----------+---------------------+
| 453445 | Z05-C01 | AAAABBBB | 2020-06-25 08:02:23 |
| 453446 | Z05-C02 | AAAABBBB | 2020-06-25 08:04:55 |
| 453447 | Z03-C01 | CCCCDDDD | 2020-06-25 08:05:19 |
| 453448 | Z02-C02 | AAAABBBB | 2020-06-25 08:05:23 |
| 453449 | Z07-C03 | CCCCDDDD | 2020-06-25 08:09:08 |
| 453450 | Z07-C04 | CCCCDDDD | 2020-06-25 08:10:01 |
| 453451 | Z04-C04 | AAAABBBB | 2020-06-25 08:11:44 |
| 453452 | Z04-C01 | AAAABBBB | 2020-06-25 08:11:59 |
| 453453 | Z04-C03 | AAAABBBB | 2020-06-25 08:12:06 |
| 453454 | Z05-C03 | AAAABBBB | 2020-06-25 08:13:00 |
+--------+----------------+----------+---------------------+
camera_id
распадается следующим образом: <Zone ID>-<Camera ID>
, а <Camera ID>
обычно не имеет значения; автомобиль, обнаруженный Z05-C01
, эквивалентен тому же автомобилю, обнаруженному Z05-C04
.
Я могу быстро GROUP BY
zone_camera_id
использовать LEFT()
, например:
SELECT Count(*) AS scan_count,
LEFT(zone_camera_id, 3) AS zone
FROM vehicle_scans
WHERE plate = 'AAAABBBB'
GROUP BY LEFT(zone_camera_id, 3)
И я вижу:
+------------+------+
| scan_count | zone |
+------------+------+
| Z05 | 3 |
| Z02 | 1 |
| Z04 | 3 |
+------------+------+
Это отличная информация, однако она не дает никакого представления о «пути», который выбрал водитель. Этот запрос не имеет представления о временной последовательности, так что если драйвер запускается в Z02
, переходит в Z05
и * возвращается в * Z02
, эти Z02
сканирования будут смешиваться вместе.
Что я хочу сделать, так это удалить "повторяющиеся" сканирования, когда водитель сканировался несколько раз в одной и той же зоне подряд (не покидал зону, как в ID=453445,453446
, но НЕ ID=453454
когда водитель вернулся), но так и не покинул зону. По сути, я хочу знать, когда водитель вошел в зону и покинул зону, без посещения другой зоны в течение этого периода времени .
Я хочу определить, сколько времени каждый автомобиль провел в каждой зоне непрерывно, даже если они вернутся в эту зону позже, примерно так:
+---------+------------+---------------------+---------------------+
| zone_id | scan_count | enter_time | exit_time |
+---------+------------+---------------------+---------------------+
| Z05 | 2 | 2020-06-25 08:02:23 | 2020-06-25 08:04:55 |
| Z02 | 1 | 2020-06-25 08:05:23 | 2020-06-25 08:05:23 |
| Z04 | 3 | 2020-06-25 08:11:44 | 2020-06-25 08:12:06 |
| Z05 | 1 | 2020-06-25 08:13:00 | 2020-06-25 08:13:00 |
+---------+------------+---------------------+---------------------+
Z05
появляется дважды, потому что они посетили зону дважды, с двумя другими посещениями зоны между ними.
Вот что я пробовал, используя Min()
и Max()
:
SELECT Count(*) AS scan_count,
LEFT(camera_zone_id, 3) AS zone_id,
Min(timestamp) AS enter_time,
Max(timestamp) AS exit_time
FROM vehicle_scans
WHERE plate = 'AAAABBBB'
GROUP BY LEFT(camera_zone_id, 3)
ORDER BY enter_time
Это отличная информация, и она соответствует структуре моего желаемого результата, однако значения Min()
и Max()
отражают абсолютные минимальные и максимальные временные метки для сканирований в этой зоне, в отличие от минимальных и максимальных временных меток. для последовательностей сканирования в особых зонах. В приведенных выше случаях, например с AAAABBBB
, транспортное средство начинается в Z05
, посещает еще две зоны и затем возвращается в Z05
. В приведенном выше запросе используется первое сканирование Z05
и самое последнее сканирование Z05
, хотя между ними были еще две посещенные зоны (Z02
и Z04
). Я ищу каждое непрерывное "посещение" зоны в отдельной строке, удаляя "повторяющиеся" сканированные изображения, в то время как они продолжают сканироваться в LEFT(camera_zone_id, 3)
.
Есть ли метод на основе SQL для группировки этих строк в непрерывную последовательность?
Спасибо!
1 ответ
Это может быть проблема с зазорами и островками, но вам нужно закрепить это пластиной.
Разница номеров строк удобна:
select plate, left(camera_zone_id, 3), min(timestamp), max(timestamp)
from (select vs.*,
row_number() over (partition by plate, left(camera_zone_id, 3) order by timestamp) as seqnum_pc,
row_number() over (partition by plate order by timestamp) as seqnum_p
from vehicle_scans vs
) vs
group by plate, (seqnum_pc - seqnum_p)
Похожие вопросы
Новые вопросы
mysql
MySQL — это бесплатная система управления реляционными базами данных (RDBMS) с открытым исходным кодом, которая использует язык структурированных запросов (SQL). НЕ ИСПОЛЬЗУЙТЕ этот тег для других БД, таких как SQL Server, SQLite и т. д. Это разные БД, которые используют свои собственные диалекты SQL для управления данными. В вопросе всегда указывайте точную версию сервера. Версии 5.x сильно отличаются по своим возможностям от версий 8+.