bookings(booking_id, room_id, start_at, end_at)
Return every pair of different bookings for the same room whose time ranges overlap. A booking that ends exactly when another starts does not overlap.
Return room_id, booking_id_1 and booking_id_2 with the smaller id first,
so each clashing pair appears once, ordered by room then by both ids.
Two ranges overlap when each one starts before the other ends. Writing the condition that way is shorter and handles containment for free.
Tables
bookings
booking_id room_id start_at end_at
---------- ------- ------------------- -------------------
1 100 2026-07-01 09:00:00 2026-07-01 11:00:00
2 100 2026-07-01 10:00:00 2026-07-01 12:00:00
3 100 2026-07-01 12:00:00 2026-07-01 13:00:00
4 200 2026-07-01 09:00:00 2026-07-01 17:00:00
5 200 2026-07-01 10:00:00 2026-07-01 11:00:00
6 300 2026-07-01 09:00:00 2026-07-01 10:00:00
Expected result
room_id booking_id_1 booking_id_2
------- ------------ ------------
100 1 2
200 4 5