route_id (PK), station_code, date, departure_time,
executor_capacity_cm3, route_score (A/B/C), created_atIndexes: date, station_code
stop_id (PK), route_id (FK→routes), stop_code, lat, lng,
type (delivery/pickup/depot), zone_idUnique: (route_id, stop_code)
Index: route_id
id (PK), route_id (FK→routes), stop_code, planned_sequence (1,2,3...)Unique: (route_id, stop_code)
id (PK), route_id (FK→routes), stop_code, actual_sequence, recorded_atUnique: (route_id, stop_code)
id (PK), route_id (FK→routes, unique),
total_planned_distance_km, total_actual_distance_km,
distance_delta_km, distance_delta_percent,
order_matched_stops, order_match_percentage, prefix_match_count1:1 with routes
routes ┬──── stops
├──── planned_route_sequence
├──── actual_route_sequence
└──── route_metrics (1:1)
- Plan: Insert route → stops → planned sequence
- Execute: Record actual sequence as stops visited
- Analyze: Compute metrics comparing planned vs actual
Get route with actual sequence:
SELECT s.lat, s.lng, a.actual_sequence
FROM actual_route_sequence a
JOIN stops s ON a.route_id = s.route_id
AND a.stop_code = s.stop_code
WHERE a.route_id = 'ROUTE_ID'
ORDER BY a.actual_sequence;Compare planned vs actual:
SELECT p.stop_code, p.planned_sequence, a.actual_sequence
FROM planned_route_sequence p
LEFT JOIN actual_route_sequence a ON p.route_id = a.route_id
AND p.stop_code = a.stop_code
WHERE p.route_id = 'ROUTE_ID';- Normalized: Stops separate from sequences
- Fast: Indexed on route_id, date
- Analytics-ready: Pre-computed metrics
- Integrity: Foreign keys with CASCADE delete
- Route optimization: Compare algorithm plan vs reality
- Driver performance: Measure sequence compliance
- Capacity planning: Analyze vehicle utilization
- Quality scoring: Route grades (A/B/C) with detailed metrics
- 5 tables, 8 indexes
- 1:many routes→stops, routes→sequences
- 1:1 routes→metrics
- Supports date-based partitioning if needed
