Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save stebazzi/7f9d68f04df6ff91a49e8e6c646abed1 to your computer and use it in GitHub Desktop.
Save stebazzi/7f9d68f04df6ff91a49e8e6c646abed1 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…
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