每天中每个组的前3名-SQL Lite

时间:2019-05-25 02:57:20

标签: sqlite

我目前正在学习如何使用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上的其他解决方案引用了在SQL Lite上尝试时不会执行的date_time和date_format函数-在SQL Lite上可以使用的查询是什么?

理想情况下,会有以下内容:

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

这将是从午夜到凌晨1:00的前3个接送地点的输出。此时间范围必须适用于所有日期,即1/1至1/31,而不仅仅是我提供的示例的1/1。

更新: 将时间戳记的格式更改为YYYY-MM-DD HH:MM:SS格式,因此我现在可以使用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 AM和2:00 AM之间,而不是12:00 AM和1:00 AM之间吗?删除查询中的“ =”符号不会导致返回任何结果。而且我不希望一天中的每个小时都执行此操作-是否可以通过一个查询按小时进行输出?

1 个答案:

答案 0 :(得分:0)

您的数据使用的时间戳字符串格式m/d/YYYY H:MM不太好。 sqlite date and time functions不能使用它,也不能对其进行有意义的排序以进行排序,并且通常在sqlite中很难使用。请记住,sqlite does not have专用的日期或时间类型,只是字符串或数字,因此您使用的格式必须遵守这些类型的规则。因此,您的第一步是通过任何方式修复这些时间戳。以下内容假设您将它们更改为YYYY-mm-dd HH:MM之类的字符串,如2017-01-01 00:01,或其他兼容格式。它还假定您使用的是最新的sqlite版本,因为它使用的是在window functions中添加的3.25。

(编辑:您似乎正在使用here中的NYC出租车数据,该数据的时间戳格式已经很好,并且很容易导入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

将提供2017年1月纽约市绿色出租车数据

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 shell通过以下方式创建的测试表:

sqlite> .mode csv
sqlite> .import '|curl -s https://s3.amazonaws.com/nyctlc/trip+data/green_tripdata_2017-01.csv | sed 2d' GreenCabs2017