Топ-3 каждой группы по времени суток - SQL Lite - PullRequest
0 голосов
/ 25 мая 2019

В настоящее время я изучаю, как использовать SQL Lite, и хотел бы отсортировать топ-3 самых популярных мест получения по часам.У меня есть миллионы строк данных с интересующими столбцами: lpep_pickup_datetime (время получения) и POLocationID (место получения).

Я бы хотел попасть в топ-3 самых популярных мест получения по часам.

Вот пример данных:

    +----------------------+--------------+-----------------+
    | lpep_pickup_datetime | PULocationID | passenger_count |
    +----------------------+--------------+-----------------+
    | 1/1/2017 0:01        |           42 |               1 |
    | 1/1/2017 0:03        |           75 |               1 |
    | 1/1/2017 0:04        |           82 |               5 |
    | 1/1/2017 0:01        |          255 |               1 |
    | 1/1/2017 0:00        |          166 |               1 |
    | 1/1/2017 0:00        |          179 |               1 |
    | 1/1/2017 0:02        |           74 |               1 |
    | 1/1/2017 0:15        |          112 |               1 |
    | 1/1/2017 0:06        |           36 |               1 |
    | 1/1/2017 0:14        |          127 |               5 |
    | 1/1/2017 0:01        |           41 |               1 |
    | 1/1/2017 0:31        |           97 |               1 |
    | 1/1/2017 0:01        |          255 |               5 |
    | 1/1/2017 0:00        |           70 |               1 |
    | 1/1/2017 0:03        |          255 |               1 |
    | 1/1/2017 0:03        |           82 |               1 |
    | 1/1/2017 0:00        |           36 |               1 |
    | 1/1/2017 0:01        |            7 |               1 |
    +----------------------+--------------+-----------------+

Попытка сделать это на SQLLiteStudio 3.2.1 - может, мне просто нужно использовать полный набор MySQL, чтобы иметь возможность использовать нужные функции?

SELECT 
PULocationID, count(PULocationID)
FROM GreenCabs2017
GROUP BY PULocationID
ORDER BY count(PULocationID) DESC
LIMIT 3

Запрос, который я пробовал, возвращает только первые 3 местоположения раскладки по всему набору данных, а не по часам дня - как я смогу группировать по часам дня?Другие решения в StackExchange ссылаются на функции date_time и date_format, которые не будут выполняться, когда я пробую их на SQL Lite - какой запрос будет работать на SQL Lite?

В идеале должно быть что-то вроде следующего:

+-------------+--------------+-----------------+
| Time of Day | PULocationID | PULocationCount |
+-------------+--------------+-----------------+
| 0:00        |           74 |             677 |
| 0:00        |           65 |             333 |
| 0:00        |           55 |             220 |
+-------------+--------------+-----------------+

Это будет вывод для 3 лучших мест получения с полуночи до 1:00 утра.Этот временной диапазон должен применяться ко всем датам, то есть от 1/1 до 1/31, а не только к 1/1, как в примере, который я предоставил.

ОБНОВЛЕНИЕ: изменен формат отметок времени на YYYY-ММ-ДД ЧЧ: ММ: СС, так что теперь я могу использовать функции datetime.

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

SELECT lpep_pickup_datetime, PULocationID, count(PULocationID)
FROM GreenCabs2017
WHERE STRFTIME('%Y', lpep_pickup_datetime) = '2017' AND
      STRFTIME('%H', lpep_pickup_datetime) <= '01' AND
      STRFTIME('%H', lpep_pickup_datetime) >= '00'
GROUP BY PULocationID
ORDER BY count(PULocationID) DESC
LIMIT 3

Это дало вывод

+----------------------+--------------+---------------------+
| lpep_pickup_datetime | PULocationID | count(PULocationID) |
+----------------------+--------------+---------------------+
| 1/31/2017 1:13       |          255 |                7845 |
| 1/31/2017 1:04       |            7 |                4596 |
| 1/31/2017 1:07       |           82 |                3892 |
+----------------------+--------------+---------------------+

Но столбец lpep_pickup_datetime по-прежнему указывает, что это будет между 1:00 и 2:00, а не 12:00 и 1:00 утра?Удаление знака "=" в запросе не приводит к получению результатов.И я бы предпочел не делать этого каждый час в день - есть ли способ получить вывод по часам через один запрос?

1 Ответ

0 голосов
/ 25 мая 2019

Формат строки метки времени, используемый вашими данными, m/d/YYYY H:MM, не очень хорош.Он не может быть использован sqlite функциями даты и времени , не может быть осмысленно упорядочен для сортировки, и в целом очень трудно работать в sqlite.Помните, что sqlite не имеет выделенных типов даты или времени, только строки или числа, поэтому используемый вами формат должен подчиняться правилам этих типов.Итак, ваш первый шаг - каким-либо образом исправить эти временные метки.Далее предполагается, что вы изменили их на YYYY-mm-dd HH:MM строк, таких как 2017-01-01 00:01 или другой совместимый формат.Также предполагается, что вы используете довольно свежий выпуск sqlite, так как он использует оконные функции , которые были добавлены в 3.25.

(Изменить: вы, похоже, используете данные такси Нью-Йорка из here , у которого уже есть временные метки в хорошем формате, и который удобен для простого импорта в sqlite. Это очень просто исправить.)

Учитывая все это, этот запрос:

WITH ranked AS
 (SELECT hour, PULocationID, pickups
       , row_number() OVER (PARTITION BY hour ORDER BY pickups DESC) AS rn
  FROM (SELECT strftime('%H:00', lpep_pickup_datetime) AS hour
             , PULocationID
             , count(*) AS pickups
        FROM GreenCabs2017
        GROUP BY strftime('%H:00', lpep_pickup_datetime), PULocationID))
SELECT * FROM ranked
WHERE rn <= 3
ORDER BY hour, rn

предоставит, для данных Green Cab Нью-Йорка за январь 2017 года

hour        PULocationID  pickups     rn        
----------  ------------  ----------  ----------
00:00       255           4224        1         
00:00       7             2518        2         
00:00       82            2135        3         
01:00       255           3621        1         
01:00       7             2078        2         
01:00       256           1870        3         
02:00       255           3261        1         
02:00       256           1798        2         
02:00       7             1676        3         
03:00       255           2854        1         
03:00       256           1589        2         
03:00       7             1475        3       

и т. Д.

По сути, он подсчитывает количество раз, которое каждое местоположение появляется в каждый час, идля каждого часа присваивает каждому местоположению номер строки на основе сортировки по этому номеру.Тогда только первые три строки каждого часа возвращаются в окончательном внешнем выборе.Вы также можете использовать rank() или dense_rank() вместо row_number(), которые потенциально могут возвращать более 3 строк в час в случае связей, но также более точно отражают наиболее популярные местоположения в этих случаях.


(Этот запрос имеет большую выгоду от наличия индекса группы по выражению:

CREATE INDEX greencabs2017_idx_hour_loc ON GreenCabs2017(strftime('%H:00', lpep_pickup_datetime), PULocationID);

)

Тестовая таблица, созданная из оболочки sqlite3 с помощью:

sqlite> .mode csv
sqlite> .import '|curl -s https://s3.amazonaws.com/nyctlc/trip+data/green_tripdata_2017-01.csv | sed 2d' GreenCabs2017
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...