| 209 | |
| 210 | = Relational Algebra = |
| 211 | |
| 212 | |
| 213 | == 6. Top selling routes for transport organizers == |
| 214 | ==== Original Query |
| 215 | {{{ |
| 216 | CREATE VIEW top_selling_routes_view AS |
| 217 | WITH route_stats AS ( |
| 218 | SELECT |
| 219 | r.route_id, |
| 220 | from_loc.name AS from_location_name, |
| 221 | to_loc.name AS to_location_name, |
| 222 | to_org.company_name AS transport_organizer_name, |
| 223 | COUNT(tk.ticket_id) AS total_tickets_sold, |
| 224 | SUM(p.total_price)::numeric(38,2) AS total_revenue, |
| 225 | AVG(p.total_price)::numeric(38,2) AS avg_ticket_price |
| 226 | FROM route r |
| 227 | JOIN transport_organizer to_org |
| 228 | ON r.transport_organizer_id = to_org.transport_organizer_id |
| 229 | JOIN location from_loc |
| 230 | ON r.from_location_id = from_loc.location_id |
| 231 | JOIN location to_loc |
| 232 | ON r.to_location_id = to_loc.location_id |
| 233 | JOIN trip tr ON r.route_id = tr.route_id |
| 234 | JOIN ticket tk ON tr.trip_id = tk.trip_id |
| 235 | JOIN payment p ON tk.payment_id = p.payment_id |
| 236 | GROUP BY r.route_id, from_loc.name, to_loc.name, to_org.company_name |
| 237 | ), |
| 238 | max_tickets AS ( |
| 239 | SELECT MAX(total_tickets_sold) AS max_sold |
| 240 | FROM route_stats |
| 241 | ) |
| 242 | SELECT rs.* |
| 243 | FROM route_stats rs, max_tickets mt |
| 244 | ORDER BY rs.total_tickets_sold DESC; |
| 245 | }}} |
| 246 | |
| 247 | == Results (Relational Algebra) == |
| 248 | {{{ |
| 249 | J1 = route ⨝ transport_organizer |
| 250 | J2 = J1 ⨝ from_loc |
| 251 | J3 = J2 ⨝ to_loc |
| 252 | J4 = J3 ⨝ trip |
| 253 | J5 = J4 ⨝ ticket |
| 254 | J6 = J5 ⨝ payment |
| 255 | |
| 256 | G1 = γ(route_id, from_loc.name, to_loc.name, to_org.company_name; |
| 257 | COUNT(ticket_id) → total_tickets_sold, |
| 258 | SUM(total_price) → total_revenue, |
| 259 | AVG(total_price) → avg_ticket_price)(J6) |
| 260 | |
| 261 | M1 = γ(; MAX(total_tickets_sold) → max_sold)(G1) |
| 262 | |
| 263 | Result = τ_desc(total_tickets_sold)(G1 × M1) |
| 264 | }}} |
| 265 | |
| 266 | == Analysis (Optimizations) == |
| 267 | * Push projections early to reduce carried attributes before aggregation. |
| 268 | * Join order: start with fact tables (`ticket`, `payment`) then join dimension tables (`trip`, `route`, `location`, `transport_organizer`). |
| 269 | * The `max_tickets` CTE is redundant unless we need to filter only top seller(s). |
| 270 | * Indexing opportunities: |
| 271 | - `ticket.trip_id`, `trip.route_id`, `ticket.payment_id` |
| 272 | - Foreign keys: `route.from_location_id`, `route.to_location_id`, `route.transport_organizer_id` |
| 273 | |
| 274 | == Conclusion (Rewritten SQL) == |
| 275 | {{{ |
| 276 | CREATE VIEW top_selling_routes_view AS |
| 277 | SELECT |
| 278 | r.route_id, |
| 279 | from_loc.name AS from_location_name, |
| 280 | to_loc.name AS to_location_name, |
| 281 | to_org.company_name AS transport_organizer_name, |
| 282 | COUNT(tk.ticket_id) AS total_tickets_sold, |
| 283 | SUM(p.total_price)::numeric(38,2) AS total_revenue, |
| 284 | AVG(p.total_price)::numeric(38,2) AS avg_ticket_price |
| 285 | FROM ticket tk |
| 286 | JOIN payment p ON tk.payment_id = p.payment_id |
| 287 | JOIN trip tr ON tk.trip_id = tr.trip_id |
| 288 | JOIN route r ON tr.route_id = r.route_id |
| 289 | JOIN transport_organizer to_org ON r.transport_organizer_id = to_org.transport_organizer_id |
| 290 | JOIN location from_loc ON r.from_location_id = from_loc.location_id |
| 291 | JOIN location to_loc ON r.to_location_id = to_loc.location_id |
| 292 | GROUP BY r.route_id, from_loc.name, to_loc.name, to_org.company_name |
| 293 | ORDER BY COUNT(tk.ticket_id) DESC; |
| 294 | }}} |
| 295 | |