我目前正在学习如何使用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之间吗?删除查询中的“ =”符号不会导致返回任何结果。而且我不希望一天中的每个小时都执行此操作-是否可以通过一个查询按小时进行输出?
答案 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