Last active
February 13, 2017 10:29
-
-
Save dsamojlenko/4464630 to your computer and use it in GitHub Desktop.
MySQL Stored Procedure to get upcoming bus times for a stop from GTFS data. This query includes buses that started running before midnight on the night before but continue through the current day. It also includes service additions and removals from calendar_dates. WARNING: without the proper indices, this query can be VERY slow. See my other Gi…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
DELIMITER $$ | |
DROP PROCEDURE IF EXISTS `ocdata`.`getNextTripsForStop`$$ | |
CREATE PROCEDURE `ocdata`.`getNextTripsForStop` ( | |
IN SelectedStop VARCHAR(6), | |
IN SearchDateTime DATETIME | |
) | |
BEGIN | |
SET @StopID = SelectedStop; | |
SET @DateToday = SearchDateTime; | |
SET @DateYesterday = DATE_SUB(@DateToday, INTERVAL 1 DAY); | |
SET @DateTomorrow = DATE_ADD(@DateToday, INTERVAL 1 DAY); | |
SET @monday = IF(LCASE(DATE_FORMAT(@DateToday,'%W')) = 'monday', 1, NULL); | |
SET @tuesday = IF(LCASE(DATE_FORMAT(@DateToday,'%W')) = 'tuesday', 1, NULL); | |
SET @wednesday = IF(LCASE(DATE_FORMAT(@DateToday,'%W')) = 'wednesday', 1, NULL); | |
SET @thursday = IF(LCASE(DATE_FORMAT(@DateToday,'%W')) = 'thursday', 1, NULL); | |
SET @friday = IF(LCASE(DATE_FORMAT(@DateToday,'%W')) = 'friday', 1, NULL); | |
SET @saturday = IF(LCASE(DATE_FORMAT(@DateToday,'%W')) = 'saturday', 1, NULL); | |
SET @sunday = IF(LCASE(DATE_FORMAT(@DateToday,'%W')) = 'sunday', 1, NULL); | |
SET @ymonday = IF(LCASE(DATE_FORMAT(@DateYesterday,'%W')) = 'monday', 1, NULL); | |
SET @ytuesday = IF(LCASE(DATE_FORMAT(@DateYesterday,'%W')) = 'tuesday', 1, NULL); | |
SET @ywednesday = IF(LCASE(DATE_FORMAT(@DateYesterday,'%W')) = 'wednesday', 1, NULL); | |
SET @ythursday = IF(LCASE(DATE_FORMAT(@DateYesterday,'%W')) = 'thursday', 1, NULL); | |
SET @yfriday = IF(LCASE(DATE_FORMAT(@DateYesterday,'%W')) = 'friday', 1, NULL); | |
SET @ysaturday = IF(LCASE(DATE_FORMAT(@DateYesterday,'%W')) = 'saturday', 1, NULL); | |
SET @ysunday = IF(LCASE(DATE_FORMAT(@DateYesterday,'%W')) = 'sunday', 1, NULL); | |
SELECT stop_name, | |
route_short_name, | |
trip_headsign, | |
IF(arrival_time >= '24:00:00', SUBTIME(arrival_time,'24:00:00'),arrival_time) AS ArrivalTime, | |
ArrivalDate, | |
CONCAT(ArrivalDate, ' ', IF(arrival_time >= '24:00:00', SUBTIME(arrival_time,'24:00:00'),arrival_time)) AS ArrivalDateTime | |
FROM ( | |
SELECT s.stop_name, | |
r.route_short_name, | |
t.trip_headsign, | |
st.arrival_time, | |
DATE(IF(st.arrival_time >= '24:00:00', DATE_ADD(@DateYesterday, INTERVAL 1 DAY), @DateYesterday)) AS ArrivalDate | |
FROM stops s | |
INNER JOIN stop_times st ON s.stop_id = st.stop_id | |
INNER JOIN trips t ON st.trip_id = t.trip_id | |
INNER JOIN routes r ON t.route_id = r.route_id | |
INNER JOIN calendar c ON t.service_id = c.service_id | |
WHERE c.service_id IN ( | |
SELECT service_id | |
FROM calendar c | |
WHERE DATE_FORMAT(@DateYesterday, '%Y%m%d') BETWEEN c.start_date AND c.end_date | |
AND ( | |
c.monday = @ymonday | |
OR c.tuesday = @ytuesday | |
OR c.wednesday = @ywednesday | |
OR c.thursday = @ythursday | |
OR c.friday = @yfriday | |
OR c.saturday = @ysaturday | |
OR c.sunday = @ysunday | |
) | |
AND service_id NOT IN ( | |
SELECT service_id FROM calendar_dates WHERE date = @DateYesterday AND exception_type = 2 | |
) | |
UNION | |
SELECT c.service_id | |
FROM calendar c | |
INNER JOIN calendar_dates cd ON c.service_id = cd.service_id | |
WHERE cd.exception_type = 1 | |
AND cd.date = @DateYesterday | |
) | |
AND s.stop_code = @StopID | |
HAVING CONCAT(ArrivalDate, ' ', arrival_time) > @DateToday | |
UNION | |
SELECT s.stop_name, | |
r.route_short_name, | |
t.trip_headsign, | |
st.arrival_time, | |
DATE(IF(st.arrival_time >= '24:00:00', DATE_ADD(@DateToday, INTERVAL 1 DAY), @DateToday)) AS ArrivalDate | |
FROM stops s | |
INNER JOIN stop_times st ON s.stop_id = st.stop_id | |
INNER JOIN trips t ON st.trip_id = t.trip_id | |
INNER JOIN routes r ON t.route_id = r.route_id | |
INNER JOIN calendar c ON t.service_id = c.service_id | |
WHERE c.service_id IN ( | |
SELECT service_id | |
FROM calendar c | |
WHERE DATE_FORMAT(@DateToday, '%Y%m%d') BETWEEN c.start_date AND c.end_date | |
AND ( | |
c.monday = @monday | |
OR c.tuesday = @tuesday | |
OR c.wednesday = @wednesday | |
OR c.thursday = @thursday | |
OR c.friday = @friday | |
OR c.saturday = @saturday | |
OR c.sunday = @sunday | |
) | |
AND service_id NOT IN ( | |
SELECT service_id FROM calendar_dates WHERE date = @DateToday AND exception_type = 2 | |
) | |
UNION | |
SELECT c.service_id | |
FROM calendar c | |
INNER JOIN calendar_dates cd ON c.service_id = cd.service_id | |
WHERE cd.exception_type = 1 | |
AND cd.date = @DateToday | |
) | |
AND s.stop_code = @StopID | |
HAVING CONCAT(ArrivalDate, ' ', arrival_time) > @DateToday | |
) a | |
HAVING ArrivalDateTime BETWEEN @DateToday AND DATE_ADD(@DateToday, INTERVAL 1 HOUR) | |
ORDER BY ArrivalDateTime; | |
END; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi Dave,
I tried to solve the problem between 11.00pm and 11.59.59pm without success.
The only working solution that I found is to change the line WHERE arrival_time BETWEEN TIME(NOW()) AND TIME(DATE_ADD(NOW(), INTERVAL 1 HOUR))
with simply
where arrival_time >= NOW()
but I don't like it because of the uncorrect order arrival time
Do you have any other possible solution?